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:
In order to follow this tutorial, you will need:
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:
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:
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
:
You will be prompted to pick a preset, select Manually select features
:
Select Babel
and Router
:
When asked if you want to use history mode for Router type 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 serverIn 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.
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:
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>© {{ 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>
.
<v-navigation-drawer>
is used in conjunction with the <v-app-bar>
component to allow you to navigate through the routes of your application<v-main>
component is where the views of your application will be displayed<v-footer>
component is where the footer of your application will be displayedNow 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
.
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
created()
field will be used to change the application theme to light because by default it was set to darkAdd 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>© {{ 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
.
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 datausers
, categories
, products
, inventory
, and orders
route will allow you to manage the documents in the users
, categories
, products
, inventories
, and orders
collection respectivelyIn 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