Vue MEVN Full Stack CRUD Web Application Tutorial

Full-stack web development is not new in town; it has been here for a while. However, learning full-stack requires tons of efforts to put in, and you need to challenge yourself to sharpen your skills in this full-stack domain.

In general, the frontend is made of HTML and CSS, which frontend developers develop; the front end is not limited to few lines of markup and CSS. Rather it takes more than that; you need to have a thorough knowledge of CSS libraries Bootstrap, Bulma, Pure, Zurb, Skeleton etc., to build the responsive UI and SEO friendly coding. It also has many essentials that need to be considered to build a robust, device and SEO friendly user interface.

Similarly, backend development has another important role to play in web application development. Backend development is responsible for handling the various features and functionalities of the application; it is also known as server-side development.

To deal with server-side development, you must know some programming languages (JavaScript, PHP, Ruby, Python, Java etc.), frontend frameworks (Vue, Angular, React etc.), Databases (SQL, NoSQL) and most importantly, REST API.

This Vue MEVN Stack tutorial will show you how to build a Vue full-stack CRUD web application. This guide will teach you everything from scratch that will help you create the VUE CRUD app. We will create a separate frontend and backend and combine both to create, read, update, and delete operation using the REST API and store the vue crud application data in the MongoDB database.

Vue JS MEVN Stack CRUD Operation Example

Here are the topics we are going to cover in this profound vue full stack web development tutorial.

  • Step 1: Set Up Vue Environment
  • Step 2: Install Axios Package
  • Step 3: Create CRUD Components
  • Step 4: Set Up Routes and Navigation
  • Step 5: Build Node Server
  • Step 6: Create Todo
  • Step 7: Read All Todos + Delete Todo
  • Step 8: Update Todo Object
  • Step 9: Start Vue + Node Servers

Set Up Vue Environment

To set up the vue development environment, respectively install vue cli, install vue new app, enter into the app.

npm install -g @vue/cli
vue create vue-todo-app
cd vue-todo-app

Plus, install the bootstrap library and import it inside the src/main.js file.

npm install bootstrap
import 'bootstrap/dist/css/bootstrap.min.css'

Install Axios Package

In this section, you will install the Axios package in the vue app, and it will let you make a Promise-based HTTP request.

npm install axios

Create CRUD Components

Next, we will formulate three vue components or file in the next step, and these templates will manage the CRUD operations.

=> AddTodo.vue

=> ListTodo.vue

=> UpdateTodo.vue

Routes and Navigation

Next, install vue-router package using the below command.

npm install vue-router

Now, open src/main.js and import the VueRouter module from the ‘vue-router’ package, and define the routes that need to invoke the navigation in the vue crud app.

import Vue from 'vue';
import App from './App.vue';

import 'bootstrap/dist/css/bootstrap.min.css';

import VueRouter from 'vue-router'
Vue.use(VueRouter)


const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: [
    { 
      path: '/create-todo',
      name: 'create-todo',
      component: () => import('./components/AddTodo.vue')
    },
    { 
      path: '/show-list',
      name: 'show-list',
      component: () => import('./components/ListTodo.vue')
    },
    { 
      path: '/edit',
      name: 'edit',
      component: () => import('./components/UpdateTodo.vue')
    }
  ]
});

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

Create a navbar to navigate in our todo app, we have to add the router-view directive and routes link in the src/App.vue file.

<template>
  <div>
    <div class="d-flex justify-content-center bd-highlight p-3 mb-2 bg-info">
      <div class="p-2 bd-highlight">
        <strong>
          <router-link class="nav-link link-light pr-3" to="/create-todo">
             Add Todo
          </router-link>
        </strong>
      </div>
      <div class="p-2 bd-highlight">
        <strong>
          <router-link class="nav-link link-light pr-3" to="/show-list">
             Show Todos
          </router-link>
        </strong>
      </div>
    </div>    

    <div class="container mt-4">
      <router-view></router-view>
    </div>
  </div>
</template>

Build Node Server (Node + Express + MongoDB)

Create a ‘backend’ in your vue app’s root, all the server-side code conjugated inside here. So, run the below command to create a specific package.json file.

npm init

Next, execute the provided command to add the required packages, install nodemon as a dev dependency and free from restarting the server all over again.

npm install mongoose body-parser express cors
npm install nodemon --save-dev

Create the todo schema, consequently first create Todo.js and there after update the backend/Todo.js with below code.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

let todoSchema = new Schema({
  title: {
    type: String
  }
}, {
    collection: 'todos'
  })

module.exports = mongoose.model('Todo', todoSchema)

Set up the database to store the todo records, create db.js and insert the following code in backend/db.js file.

module.exports = {
    database: 'mongodb://localhost:27017/mevndb'
};

Create routes of our API by creating a todo.route.js and respectively define the REST API routes.

Update the backend/todo.route.js file.

let mongoose = require('mongoose');
let express = require('express');
let router = express.Router();

let todoSchema = require('./Todo');

router.route('/').get((req, res, next) => {
  todoSchema.find((error, data) => {
      if (error) {
        return next(error)
      } else {
        res.json(data)
      }
    })
})


router.route('/create-todo').post((req, res, next) => {
  todoSchema.create(req.body, (error, data) => {
    if (error) {
      return next(error)
    } else {
      console.log(data)
      res.json(data)
    }
  })
});


router.route('/get-todo/:id').get((req, res, next) => {
  todoSchema.findById(req.params.id, (error, data) => {
    if (error) {
      return next(error)
    } else {
      res.json(data)
    }
  })
})


router.route('/update-todo/:id').put((req, res, next) => {
  todoSchema.findByIdAndUpdate(req.params.id, {
    $set: req.body
  }, (error, data) => {
    if (error) {
      return next(error);
    } else {
      res.json(data)
      console.log('Todo updated')
    }
  })
})


router.route('/delete-todo/:id').delete((req, res, next) => {
  todoSchema.findByIdAndRemove(req.params.id, (error, data) => {
    if (error) {
      return next(error);
    } else {
      res.status(200).json({
        msg: data
      })
    }
  })
})

module.exports = router;

To invoke the node server, so you need to create the backend/index.js and conjugate the following code within the file.

let express = require('express');
let mongoose = require('mongoose');
let cors = require('cors');
let bodyParser = require('body-parser');
let mongoDb = require('./db');

const TodoRoute = require('./todo.route')

mongoose.Promise = global.Promise;
mongoose.connect(mongoDb.database, {
    useUnifiedTopology: true,
    useNewUrlParser: true
}).then(() => {
  console.log('Database connected!')
},
error => {
    console.log(error)
  }
)

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

app.use(cors());
app.use('/api', TodoRoute)


const port = process.env.PORT || 8888;
const server = app.listen(port, () => {
  console.log('Connected on : ' + port)
})

app.use(function (err, req, res, next) {
  if (!err.statusCode) err.statusCode = 500;
  res.status(err.statusCode).send(err.message);
});

C = CREATE

We have created REST API using node and express; in this step, we will show you how to use the Axios package to consume API and cover the create part of the entire CRUD paradigm.

Open src/components/AddTodo.vue and update the below code.

<template>
    <div>
        <h2 class="text-center mb-3">Create Todo</h2>

        <form @submit.prevent="onSubmit">
            <div class="form-group">
                <input type="text" class="form-control" v-model="TODO.title" required>
            </div>

            <div class="d-grid mt-3">
                <button class="btn btn-danger btn-block">Add</button>
            </div>
        </form>
    </div>
</template>

<script>
    import axios from "axios";

    export default {
        data() {
            return {
                TODO: {
                   title: ''
                }
            }
        },
        methods: {
            onSubmit() {
                let endpoint = 'http://localhost:8888/api/create-todo';
                
                axios.post(endpoint, this.TODO).then(() => {
                  this.TODO = {
                    title: ''
                  }
                  alert('Todo created!')
                }).catch((err) => {
                    alert(err)
                });
            }
        }
    }
</script>

R = READ & D = DELETE

In the previous step, we comprehended how to create or add todo in the database using REST API, and now we will learn to consume read and delete API. We will show the created todos list and delete the todo from the frontend and from the database.

Open src/components/ListTodo.vue and update with the recommended code.

<template>
    <div>
        <ol class="list-group list-group-numbered">
            <li v-for="todo in TODOS" :key="todo._id" class="list-group-item d-flex justify-content-between align-items-start">
                 <div class="ms-2 me-auto mb-2">
                    {{ todo.title }}
                  </div>
                  
                  <router-link class="btn text-primary" :to="{name: 'edit', params: { id: todo._id }}">&#9998;</router-link>
                  <span class="btn text-danger" @click.prevent="removeTodo(todo._id)">&#10005;</span>
            </li>
        </ol>
    </div>
</template>

<script>
    import axios from "axios";

    export default {
        data() {
            return {
                TODOS: []
            }
        },
        created() {
            let endpoint = 'http://localhost:8888/api';
            axios.get(endpoint).then((response) => {
                this.TODOS = response.data;
            }).catch(error => {
                console.log(error)
            });
        },
        methods: {
            removeTodo(id){
                let endpoint = `http://localhost:8888/api/delete-todo/${id}`;
                let todoIndex = this.TODOS.findIndex(i => i._id === id);
                
                axios.delete(endpoint).then(() => {
                    this.TODOS.splice(todoIndex, 1);
                }).catch((err) => {
                    console.log(err)
                });
            }
        }
    }
</script>

U = UPDATE

Eventually, you have to use two apis to get the todo object and display it in the todo form and use other API to update the todo in the database so update code in src/components/UpdateTodo.vue file.

<template>
    <div>
        <h2 class="text-center mb-3">Create Todo</h2>

        <form @submit.prevent="onUpdate">
            <div class="form-group">
                <input type="text" class="form-control" v-model="TODO.title" required>
            </div>

            <div class="d-grid mt-3">
                <button class="btn btn-dark btn-block">Update</button>
            </div>
        </form>
    </div>
</template>

<script>
import axios from "axios";

export default {
    data() {
        return {
            TODO: { }
        }
    },
    created() {
        let endpoint = `http://localhost:8888/api/get-todo/${this.$route.params.id}`;
        axios.get(endpoint)
        .then((response) => {
            this.TODO = response.data;
        })
    },
    methods: {
        onUpdate() {
            let endpoint = `http://localhost:8888/api/update-todo/${this.$route.params.id}`;
            axios.put(endpoint, this.TODO)
            .then((response) => {
                console.log(response)
                this.$router.push('/show-list')
            }).catch((err) => {
                alert(err)
            });
        }
    }
}
</script>

Start Vue + Node Servers

We are only left with starting the client-side and server-side; we can do it by executing the given commands.

Open the console and run the below command to start the mongo database; make sure to configure it in your system.

mongo

Open another console, and start the node server.

nodemon

Finally start the vue application.

npm run serve
http://localhost:8080/create-todo

Vue MEVN Stack CRUD

Conclusion

In this comprehensive tutorial, we learned how to develop a Full-stack web application using the MEVN (MongoDB, Express, Vue, Node) archetype, and we ascertained how to create a simple vue todo app and handle CRUD operation using the REST API built with Express.js; moreover, we saw how to store the data in the MongoDB after successfully making the HTTP requests.

We reckon you loved this MEVN Stack guide, and please let us know if you find any mistake in this Vue Full-stack tutorial