In this tutorial, we will work with Vue, Vue Router, Vuetify, and node-fetch to build the front end of an inventory management application. Vue is a JavaScript framework for building user interfaces on the web . Vue Router is the official router for the Vue framework. Vuetify is a Vue UI library with beautifully handcrafted Material Components. node-fetch is a module that allows you to make HTTP requests to API endpoints or any URL.

At the end of this tutorial you will have an application that looks like this:

completed dashboard with products, categories, inventory

Prerequisites

In order to follow this tutorial, you will need:

Creating the project root directory

In this section, we will create your project’s directory structure. Then we will initialize a Node.js project for your application client.

Open a terminal window and clone the repository that contains the back end I created in advance for this tutorial from GitHub:

git clone https://github.com/CSFM93/inventory-management-system

After running the command above you will have a directory named inventory-management-system.

Navigate into this directory:

cd inventory-management-system

The folder structure should look like this:

file layout in the server

The server directory, contains the back end for your inventory management application. The back end consists of a GraphQL server connected to a MongoDB database. In order to build this GraphQL server, I used Node.js, Docker, MongoDB, graphql-yoga, mongoose, and connect-history-api-fallback.

Inside your database you will have the following collections:

database collections

Now that you know what is happening in the back end it’s time to build the front end of your inventory management application.

Still in the inventory-management-system directory, create a subdirectory named client:

mkdir client

Navigate into the client directory:

cd client

Use the Vue CLI to create a new Vue project in the current directory:

vue create .

When asked to create a new project in the current directory type y:

Generate project directory? Y/N

You will be prompted to pick a preset, select Manually select features:

Please pick a preset

Select Babel and Router:

select babel and router

When asked if you want to use history mode for Router type y:

Use history mode for router? y

According to the Vue Router website, the default mode for Vue router is hash mode – it uses the URL hash to simulate a full URL so that the page won’t be reloaded when the URL changes. To get rid of the hash, you can use the router’s history mode, which leverages the history.

When asked where you want to place config, select In dedicated config files and when asked if you want to save these configurations for future projects type y or n.

After the Vue CLI finishes creating the project, install the missing dependencies.

First, install Vuetify using the Vue CLI by running the following command:

vue add vuetify

When asked to select a preset, choose default.

In this block of code, you have installed Vuetify . You will use this module to create the inventory management system UI without having to worry too much about CSS.

Lastly, use npm to install node-fetch:

npm install node-fetch --save

In this block of code, you have installed node-fetch.

  • node-fetch is a module that allows you to make HTTP requests to API endpoints, or any URL. You will use this module to consume the GraphQL API in the server

In this section, you created a project directory and initialized a Node.js project for your application client. In the next section, you will start building the user interface for this application.

Creating the application layout and routes

In this step, you are going to use Vuetify to create the layout and vue-router to handle the routes for the application client.

Navigate to thesrc directory:

cd src

The folder structure should look something like this:

folder structure for project

Open your App.vue file:

nano App.vue

Remove the <style> component and replace the contents in the <template> component with the following:

<template>
  <v-app id="app">
    <v-navigation-drawer v-model="drawer" app clipped>
      <v-list dense v-for="route in routes" :key="route.title">
        <v-list-item link @click="navigateTo(route.path)">
          <v-list-item-action>
            <v-icon>{{route.icon}}</v-icon>
          </v-list-item-action>
          <v-list-item-content>
            <v-list-item-title>{{route.title}}</v-list-item-title>
          </v-list-item-content>
        </v-list-item>
      </v-list>
    </v-navigation-drawer>
    <v-app-bar app clipped-left>
      <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
      <v-toolbar-title>Application</v-toolbar-title>
    </v-app-bar>
    <v-main>
      <v-container class="fill-height" fluid>
        <v-row align="center" justify="center">
          <v-col>
            <router-view :key="$route.fullPath"></router-view>
          </v-col>
        </v-row>
      </v-container>
    </v-main>
    <v-footer app>
      <span>&copy; {{ new Date().getFullYear() }}</span>
    </v-footer>
  </v-app>
</template>

In the block of code above, you have added inside the <-app> component the following components, <v-navigation-drawer> , <v-app-bar>, <v-main>, and <v-footer>.

  • The <v-navigation-drawer> is used in conjunction with the <v-app-bar> component to allow you to navigate through the routes of your application
  • The <v-main> component is where the views of your application will be displayed
  • The <v-footer> component is where the footer of your application will be displayed

Now replace the contents inside your <script> component with the following:

<script>
export default {
  name: "App",
  data: () => ({
    drawer: null,
    routes: [
      { path: "home", title: "Dashboard", icon: "mdi-view-dashboard" },
      { path: "users", title: "Users", icon: "mdi-cog" },
      { path: "categories", title: "Categories", icon: "mdi-cog" },
      { path: "products", title: "Products", icon: "mdi-cog" },
      { path: "inventory", title: "Inventory", icon: "mdi-cog" },
      { path: "orders", title: "Orders", icon: "mdi-cog" },
    ],
  }),
  created() {
    this.$vuetify.theme.light = true;
  },
}
</script>

In the block of code above, you have created the data field and the created() field for the App.vue.

  • The data field contains two subfields, drawer and routes. drawer will be used to control the application navigation drawer and routes contains the data that will be used to generate the items in the drawer
  • The created() field will be used to change the application theme to light because by default it was set to dark

Add the following code below to the created() field:

<script>
export default {
 . . .

  methods: {
    navigateTo(route) {
      if (this.$route.name !== route) {
        this.$router.push({ name: route }).catch((error) => {
          console.log(error)
        });
      }
    },
  },
}
</script>

In the block of code above, you have added the methods field, and inside this method you added a method named navigateTo(). The navigateTo() method receives as an argument a string named route, using conditional logic this method checks if the current route is not equal to route and if that is the case it navigates to this received route. This method will be called whenever you click an item in the <v-navigation-drawer>.

Your App.vue should look something like this:

<template>
  <v-app id="app">
    <v-navigation-drawer v-model="drawer" app clipped>
      <v-list dense v-for="route in routes" :key="route.title">
        <v-list-item link @click="navigateTo(route.path)">
          <v-list-item-action>
            <v-icon>{{route.icon}}</v-icon>
          </v-list-item-action>
          <v-list-item-content>
            <v-list-item-title>{{route.title}}</v-list-item-title>
          </v-list-item-content>
        </v-list-item>
      </v-list>
    </v-navigation-drawer>
    <v-app-bar app clipped-left>
      <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
      <v-toolbar-title>Application</v-toolbar-title>
    </v-app-bar>
    <v-main>
      <v-container class="fill-height" fluid>
        <v-row align="center" justify="center">
          <v-col>
            <router-view :key="$route.fullPath"></router-view>
          </v-col>
        </v-row>
      </v-container>
    </v-main>
    <v-footer app>
      <span>&copy; {{ new Date().getFullYear() }}</span>
    </v-footer>
  </v-app>
</template>

<script>
export default {
  name: "App",
  data: () => ({
    drawer: null,
    routes: [
      { path: "home", title: "Dashboard", icon: "mdi-view-dashboard" },
      { path: "users", title: "Users", icon: "mdi-cog" },
      { path: "categories", title: "Categories", icon: "mdi-cog" },
      { path: "products", title: "Products", icon: "mdi-cog" },
      { path: "inventory", title: "Inventory", icon: "mdi-cog" },
      { path: "orders", title: "Orders", icon: "mdi-cog" },
    ],
  }),
  created() {
    this.$vuetify.theme.light = true;
  },
  methods: {
    navigateTo(route) {
      if (this.$route.name !== route) {
        this.$router.push({ name: route }).catch((error) => {
          console.log(error)
        });
      }
    },
  },
}
</script>

Navigate to the router directory:

cd router

Open the index.js file:

nano index.js

Remove the line where you import the Home view component:

import Home from '../views/Home.vue'

Replace the content of the routes array with the following:

. . .

const routes = const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue')
  },
  {
    path: '/users',
    name: 'users',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  },
  {
    path: '/categories',
    name: 'categories',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  },
  {
    path: '/inventory',
    name: 'inventory',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  },
  {
    path: '/products',
    name: 'products',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  },
  {
    path: '/orders',
    name: 'orders',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  }
]

In the block of code above, you added the following routes to the routes array, home, users, categories, products, inventory, and orders.

  • The home route will display a grid of cards, each card will display a collection name and the number of documents in it, and allow you to navigate to the route that contains the collection data
  • The users, categories, products, inventory, and orders route will allow you to manage the documents in the users, categories, products, inventories, and orders collection respectively

In every route, you are lazily loading the view component. All routes contents will be displayed in the Table view component with the exception of the home route contents which will be displayed in the Home view component.

Your index.js file should look like the following:

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue')
  },
  {
    path: '/users',
    name: 'users',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  },
  {
    path: '/categories',
    name: 'categories',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  },
  {
    path: '/inventory',
    name: 'inventory',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  },
  {
    path: '/products',
    name: 'products',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  },
  {
    path: '/orders',
    name: 'orders',
    component: () => import(/* webpackChunkName: "table" */ '../views/Table.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

In this section, you have created the layout and the routes for your application client. In the next section, you will start creating views for your application client.

#vue #javascript #web-development #programming #developer

Rolling Your Own Management Application with Vue, Vue Router, Vuetify, and node-fetch
43.90 GEEK