This is a step by step MEVN stack tutorial, in this tutorial, we are going to learn how to engender MEVN stack app. (MongoDB, Express.js, Vue.js, Node.js).
I will show you how to engender a Full-stack single page application with Vue from scratch.
We will engender a simple yet best Student Record Management system. This system efficiently sanctions users to perform CRUD (ENGENDER, READ, UPDATE & EFFACE) operations.
We will create our server using Node and Express.js and store student records. We will use MongoDB. We will manage the front-end of the application with Vue.js.
So, let us start coding the MEVN Stack app with a practical example.
Create a New Vue Project
To install Vue project, we must have Vue CLI installed on our development system.
Run the following command to install Vue CLI:
# npm
npm install -g @vue/cli
# yarn
yarn global add @vue/cli
Use the following command to install the vue project.
vue create vue-mevn-stack-app
Head over to vue project:
cd vue-mevn-stack-app
Run command to start the app on the browser:
npm run serve
Adding Bootstrap in Vue 2
Let us run the below command to install the Bootstrap 4 UI Framework.
npm install bootstrap
# or
yarn add bootstrap
Import the Bootstrap framework path inside the main.js file. Now, you can use Bootstrap UI components in your vue app.
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import 'bootstrap/dist/css/bootstrap.min.css'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
Build Vue Components
Head over to src/components directory, here we have to create the following components. These components will handle the data in our full-stack Vue.Js application.
- CreateComponent.vue
- EditComponent.vue
- ListComponent.vue
Open src/CreateComponent.vue file and add the following code inside of it.
<template>
<div class="row justify-content-center">
<div class="col-md-6">
<!-- Content goes here -->
</div>
</div>
</template>
<script>
export default {
data() {
return {
}
}
}
</script>
</div>
Open src/EditComponent.vue file and place code inside of it.
<template>
<div class="row justify-content-center">
<div class="col-md-6">
<!-- Update Student content -->
</div>
</div>
</template>
<script>
export default {
data() {
return {
}
}
}
</script>
Open src/ListComponent.vue file and add the below code in it.
<template>
<div class="row justify-content-center">
<div class="col-md-6">
<!-- Display Student List -->
</div>
</div>
</template>
<script>
export default {
data() {
return {
}
}
}
</script>
Enable Vue Router
Open src/router/index.js and replace the existing code with the following code.
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: () => import('../components/CreateComponent')
},
{
path: '/view',
name: 'view',
component: () => import('../components/ListComponent')
},
{
path: '/edit/:id',
name: 'edit',
component: () => import('../components/EditComponent')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
Setting Up Navigation with Bootstrap and Router View in Vue
Go to src/App.vue file, here we define the Bootstrap Navigation component, router-view directive and the router-link directive.
The <router-link>
is the component for facilitating user navigation in a router-enabled vue app.
The <router-view>
component is the main component that is responsible for rendering the matched component for the provided path.
<template>
<div>
<!-- Nav bar -->
<nav class="navbar navbar-dark bg-primary justify-content-between flex-nowrap flex-row">
<div class="container">
<a class="navbar-brand float-left">MEVN Stack Example | LaravelCode</a>
<ul class="nav navbar-nav flex-row float-right">
<li class="nav-item">
<router-link class="nav-link pr-3" to="/">Create Student</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" to="/view">View Students</router-link>
</li>
</ul>
</div>
</nav>
<!-- Router view -->
<div class="container mt-5">
<router-view></router-view>
</div>
</div>
</template>
Add Axios in Vue.js 2 to Handle HTTP Requests
Run command to install Axios:
npm install axios
# or
yarn add axios
Axios is a promise based HTTP client for the browser and node.js,
Build Form in Vue with Bootstrap 4
We require to store the data in the MEVN stack app, so we need to build a vue form using Bootstrap Form component.
Check out our previous tutorial detailed tutorial on – Form Validation in Vue with Vuelidate.
Open components/CreateComponent.vue file, then place the following code in it.
<template>
<div class="row justify-content-center">
<div class="col-md-6">
<h3 class="text-center">Create Student</h3>
<form @submit.prevent="handleSubmitForm">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" v-model="student.name" required>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" v-model="student.email" required>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" class="form-control" v-model="student.phone" required>
</div>
<div class="form-group">
<button class="btn btn-danger btn-block">Create</button>
</div>
</form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
student: {
name: '',
email: '',
phone: ''
}
}
},
methods: {
handleSubmitForm() { }
}
}
</script>
We created a basic form with name, email and phone number field. We created a beautiful form using Bootstrap form component.
The student object works with two-way data binding approach; it merely means that any data-related changes affecting the model are immediately propagated to the matching view.
Here is the form which you can check in the browser.
Setting up Node Server Environment
Now, we need to create REST APIs using Node + Express & MongoDB in Vue application. Create backend folder at the root of Vue project.
mkdir backend && cd backend
Generate separate package.json for node server.
npm init
Run command to install the following dependencies for Node/Express js.
npm i body-parser cors express mongoose
Also, install a nodemon server as a development dependency. So that we do not need to restart every time, we change our server code.
Install nodemon as a development dependency, It automates the server starting process.
npm install nodemon
# or
yarn add nodemon
Configure & Start MongoDB Database
Create backend/database.js file at the root of your node application. Next, add the given code in it.
module.exports = {
db: 'mongodb://localhost:27017/vuecrudmevn'
}
In this tutorial, we are working with MongoDB to store students data, so you must set up MongoDB on your development system.
You can follow this tutorial for the installation guidance at Install MongoDB on macOS, Linux and Windows.
Open the terminal window and run the following command to start the MongoDB on your local machine.
mongod --config /usr/local/etc/mongod.conf
brew services start mongodb-community@4.2
mongo
Create Mongoose Model
Create models/Student.js and paste the below code inside the file. We will define name, email and phone values inside the Student model.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let studentSchema = new Schema({
name: {
type: String
},
email: {
type: String
},
phone: {
type: Number
},
}, {
collection: 'students'
})
module.exports = mongoose.model('Student', studentSchema)
Create Route in Node/Express App
Create a backend/routes directory; here, we have to create student.route.js file and place all the given below code inside of it.
const express = require('express');
const studentRoute = express.Router();
// Student model
let StudentModel = require('../models/Student');
studentRoute.route('/').get((req, res) => {
StudentModel.find((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
studentRoute.route('/create-student').post((req, res, next) => {
StudentModel.create(req.body, (error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
});
studentRoute.route('/edit-student/:id').get((req, res) => {
StudentModel.findById(req.params.id, (error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
// Update student
studentRoute.route('/update-student/:id').post((req, res, next) => {
StudentModel.findByIdAndUpdate(req.params.id, {
$set: req.body
}, (error, data) => {
if (error) {
return next(error);
} else {
res.json(data)
console.log('Student successfully updated!')
}
})
})
// Delete student
studentRoute.route('/delete-student/:id').delete((req, res, next) => {
StudentModel.findByIdAndRemove(req.params.id, (error, data) => {
if (error) {
return next(error);
} else {
res.status(200).json({
msg: data
})
}
})
})
module.exports = studentRoute;
We defined the routes these routes will communicate with the server using the Axios library. We can perform CRUD operation using the GET, POST, UPDATE & DELETE methods.
Create the backend/app.js file and place the following code that contains the Node server settings.
let express = require('express'),
cors = require('cors'),
mongoose = require('mongoose'),
database = require('./database'),
bodyParser = require('body-parser');
// Connect mongoDB
mongoose.Promise = global.Promise;
mongoose.connect(database.db, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log("Database connected")
},
error => {
console.log("Database could't be connected to: " + error)
}
)
const studentAPI = require('../backend/routes/student.route')
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cors());
// API
app.use('/api', studentAPI)
// Create port
const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
console.log('Connected to port ' + port)
})
// Find 404
app.use((req, res, next) => {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
console.error(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
});
Also, don’t forget to register the app.js value inside the “main” property in package.json file.
{
"name": "vue-mevn-stack",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"mongoose": "^5.9.10"
},
"devDependencies": {
"nodemon": "^2.0.3"
}
}
Start Node/Express App
We have built following API using Node and Express in Vue.js.
Method | API |
---|---|
GET | http://localhost:4000/api |
POST | /api/create-student |
GET | /api/edit-student/:id |
POST | /api/update-student/:id |
DELETE | /api/delete-student/:id |
Open a new terminal window and start the MongoDB:
mongo
Open a new terminal window and start the nodemon server:
nodemon
You can view server running on http://localhost:4000/api
Open another terminal window and start the vue app:
npm run serve
You can view vue app running on http://localhost:8080
Create Student Data with Axios POST
The Axios post method takes the REST API and makes the POST request to the server. It creates the student data that we are adding in the mongoDB database.
Once the data is sent to the server, you can then check the stored data on http://localhost:4000/api
Add the given below code inside the components/CreateComponent.vue file.
<template>
<div class="row justify-content-center">
<div class="col-md-6">
<h3 class="text-center">Create Student</h3>
<form @submit.prevent="handleSubmitForm">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" v-model="student.name" required>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" v-model="student.email" required>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" class="form-control" v-model="student.phone" required>
</div>
<div class="form-group">
<button class="btn btn-danger btn-block">Create</button>
</div>
</form>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
student: {
name: '',
email: '',
phone: ''
}
}
},
methods: {
handleSubmitForm() {
let apiURL = 'http://localhost:4000/api/create-student';
axios.post(apiURL, this.student).then(() => {
this.$router.push('/view')
this.student = {
name: '',
email: '',
phone: ''
}
}).catch(error => {
console.log(error)
});
}
}
}
</script>
Show Data List & Delete Data in Vue
Now, we will show the data in the tabular form using Bootstrap Table components, and we will make the axios.get() request to render the data from the server.
Add the given below code inside the components/ListComponent.vue file.
<template>
<div class="row">
<div class="col-md-12">
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="student in Students" :key="student._id">
<td>{{ student.name }}</td>
<td>{{ student.email }}</td>
<td>{{ student.phone }}</td>
<td>
<router-link :to="{name: 'edit', params: { id: student._id }}" class="btn btn-success">Edit
</router-link>
<button @click.prevent="deleteStudent(student._id)" class="btn btn-danger">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
Students: []
}
},
created() {
let apiURL = 'http://localhost:4000/api';
axios.get(apiURL).then(res => {
this.Students = res.data;
}).catch(error => {
console.log(error)
});
},
methods: {
deleteStudent(id){
let apiURL = `http://localhost:4000/api/delete-student/${id}`;
let indexOfArrayItem = this.Students.findIndex(i => i._id === id);
if (window.confirm("Do you really want to delete?")) {
axios.delete(apiURL).then(() => {
this.Students.splice(indexOfArrayItem, 1);
}).catch(error => {
console.log(error)
});
}
}
}
}
</script>
<style>
.btn-success {
margin-right: 10px;
}
</style>
To delete the student object from the database, we defined the deleteStudent() function and bound it to click event with an id parameter.
The apiURL contains the api/delete-student/:id API, to find out the index of the clicked student data index from the Students array, we took the help of findIndex()
method.
Update Data with POST Request
Add the following code inside the components/EditComponent.vue file.
<template>
<div class="row justify-content-center">
<div class="col-md-6">
<h3 class="text-center">Update Student</h3>
<form @submit.prevent="handleUpdateForm">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" v-model="student.name" required>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" v-model="student.email" required>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" class="form-control" v-model="student.phone" required>
</div>
<div class="form-group">
<button class="btn btn-danger btn-block">Update</button>
</div>
</form>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
student: { }
}
},
created() {
let apiURL = `http://localhost:4000/api/edit-student/${this.$route.params.id}`;
axios.get(apiURL).then((res) => {
this.student = res.data;
})
},
methods: {
handleUpdateForm() {
let apiURL = `http://localhost:4000/api/update-student/${this.$route.params.id}`;
axios.post(apiURL, this.student).then((res) => {
console.log(res)
this.$router.push('/view')
}).catch(error => {
console.log(error)
});
}
}
}
</script>
i hope you like this article.