In this post, we learn a simple CRUD operation where the user can create, read, delete and update some data.so let us start the MEVN Stack Tutorial From Scratch for the beginner. Before start tutorials, we need to first install Vue.js project using Vue CLI and for install CLI we need Node.js (version 8.9 or above 8.11.0+ recommended) Run the following command to install Vue CLI, if you have not installed in your machine. After successfully install you can check the version is Vue js using this command. Run this following command to install Vue.js. It takes some time to depend on your internet speed. Now, go to your Vue js project folder and run following command. After that start the Vue js dev server using the following command. Now, open project file in your favorite code editor. Go to the http://localhost:8081 URL on your browser. We install two dependencies one is vue-router and vue-axios. Install this dependency using following this command. In this Vue application, we use the bootstrap framework for styling. to install bootstrap run this command. Now import bootstrap file in main.js In src/components folder create four new following components. Now, add some view code inside the HomeComponent.vue file. After adding this component we need to import the HomeComponent.vue file inside the App.vue file. Visit http://localhost:8081/ to see HomeComponents rendering. Now create other three components. Now, configure Vue router. Inside the main.js file, write the following code for the route. Here, first import the Vue-router module and create an array for the route which has a name, path, and components as the properties. After that, we have created the router object and passed the mode history and routes array. Now, the at the last step is to define the <router-view></router-view> element in the view. It renders the component according to the routing path in our Vue application. So, add the <router-view> inside the App.vue file. Now, save the file and check the following route paths. Write the following code inside the App.vue file for Nav bar. Here we add some code navigation bar for Vue application. We need a simple form for submitting data. so let's create a form in CreateComponent.vue First, at the bottom of the code, we define the object post here use used two-way data binding the post object has two properties title and body. Second, we create one method called addPost(). when the user submits form details we will receive inside the addPost() method. we will send a POST method request to the Laravel server and to save the data into the database. Save all files and go to this URL: http://localhost:8080/create You can see the form like below. Create a new folder inside the Vue project root called API and go inside that new folder. And now, initialize the package.json file. After running this command inside the new folder a new file auto created named package.json. After that install the following node.js dependencies. using the following command. We need to also install Nodemon serve as a development dependency. because we do not need to restart every time, we change our server code.e change our server code. Now we need to create some files called All these files should be inside the root of the API folder. and write the following code inside the server.js file. After that, we need to start a node server using the following command. After running the command, our node.js server is running at port: 4000 Install MongoDB in your computer system. here I am just using the terminal for this demo because it is a simple application. Inside the API, folder creates a new file DB.js for connecting our node application with MongoDB, so this following code inside the DB.js. For the local MongoDB server, username and password may be empty. but when we create a production database we need to set all this thing. Now, import this DB.js file into the server.js file. Now, our application connects with MongoDB Database. Add some code inside the post.model.js Here we add CRUD operation code inside the post.route.js file. Inside the post model js, we write the CRUD operation in Node.js which is back end server side. so when a user requests from the clientside hits the node express server and the above function will be executed and all request sends to the database and send the response to the client, in this application we use vue.js as frontend. We use MongoDB ORM to CRUD operation from the MongoDB database. Mongoose is an ORM(Object Relational Mapping) which is used in the MongoDB database. Now, we have all setup for the CRUD operations set up on the post.route.js file. we need to import inside the server.js file. So, our finally server.js file looks like this. Import the axios and vue-axios in the main.js file. We have created the backend. Next step is to send the POST method request to the node.js API server. Remember, now we have three servers are running. Make sure, all these running fine otherwise the project won’t work. Write some code code inside the CreateComponent.vue file’s addPost() function. Now we can create the post and see in the MongoDB database. To check by the terminal, you need to open the mongo shell using the following command. After saving a row of data into database we want to display. so write some code inside the IndexComponent.vue Now you can see this inserted data on the browser. Now, when we want to edit our data we need to fetch that record from data to display on view. Then, after editing the data in the textbox and textarea, when we hit the update button, updatePost() function to send a post request to the server to update the data. After changing the database we can see the edit data from the database and also you can update the database. So, add some final code inside the IndexComponent.vue file for delete a record. Save all file, and now, you can see delete the values from the MongoDB database. So, finally, our MEVN Stack Tutorial From Scratch for the beginner is over. MEVN Stack Tutorial From Scratch for beginner
npm install -g @vue/cli
# OR
yarn global add @vue/cli
vue --version
Step: 1 Create a new Vue.js project
vue create mevnproject
cd mevnexample
npm run serve
Step:2 Install Vue dependencies.
npm install axios vue-router vue-axios --save
npm install bootstrap --save
// main.js
import Vue from 'vue'
import App from './App.vue'
import 'bootstrap/dist/css/bootstrap.min.css'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
Step 3: Create some components in Vue js
<template>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card card-default">
<div class="card-header">Home Component</div>
<div class="card-body">
I'm the Home Component component.
</div>
</div>
</div>
</div>
</template>
<script>
export default {
}
</script>
CreatComponent.vue
<template>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card card-default">
<div class="card-header">Create Component</div>
<div class="card-body">
I'm the Create Component component.
</div>
</div>
</div>
</div>
</template>
<script>
export default {
}
</script>
EditComponent.vue
// EditComponent.vue
<template>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card card-default">
<div class="card-header">Edit Component</div>
<div class="card-body">
I'm an Edit component.
</div>
</div>
</div>
</div>
</template>
<script>
export default {
}
</script>
IndexComponent.vue
// IndexComponent.vue
<template>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card card-default">
<div class="card-header">Index Component</div>
<div class="card-body">
I'm an Index component.
</div>
</div>
</div>
</div>
</template>
<script>
export default {
}
</script>
Step:4 Configure the Vue-router
// main.js
import Vue from 'vue'
import App from './App.vue'
import 'bootstrap/dist/css/bootstrap.min.css'
import VueRouter from 'vue-router';
Vue.use(VueRouter);
Vue.config.productionTip = false;
import HomeComponent from './components/HomeComponent.vue';
import CreateComponent from './components/CreateComponent.vue';
import IndexComponent from './components/IndexComponent.vue';
import EditComponent from './components/EditComponent.vue';
const routes = [
{
name: 'home',
path: '/',
component: HomeComponent
},
{
name: 'create',
path: '/create',
component: CreateComponent
},
{
name: 'posts',
path: '/posts',
component: IndexComponent
},
{
name: 'edit',
path: '/edit/:id',
component: EditComponent
}
];
const router = new VueRouter({ mode: 'history', routes: routes});
new Vue(Vue.util.extend({ router }, App)).$mount('#app');
// App.vue
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
Step:4 Create nav-bar for Vue application.
// App.vue
<template>
<div class="container">
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<ul class="navbar-nav">
<li class="nav-item">
<router-link to="/" class="nav-link">Home</router-link>
</li>
<li class="nav-item">
<router-link to="/create" class="nav-link">Create Post</router-link>
</li>
<li class="nav-item">
<router-link to="/posts" class="nav-link">Posts</router-link>
</li>
</ul>
</nav><br />
<transition name="fade">
<router-view></router-view>
</transition>
</div>
</template>
<style>
</style>
<script>
export default{
}
</script>
Step:6 Create a form in CreateComponent.vue
// CreateComponent.vue
<template>
<div>
<h1>Create A Post</h1>
<form @submit.prevent="addPost">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Title:</label>
<input type="text" class="form-control" v-model="post.title">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Body:</label>
<textarea class="form-control" v-model="post.body" rows="5"></textarea>
</div>
</div>
</div><br />
<div class="form-group">
<button class="btn btn-primary">Create</button>
</div>
</form>
</div>
</template>
<script>
export default {
data(){
return {
post:{}
}
},
methods: {
addPost(){
console.log(this.post);
}
}
}
</script>
Step: 7 Create a Node.js backend
npm init -y
{
"name": "api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
yarn add express body-parser cors mongoose
# or
npm install express body-parser cors mongoose --save
npm install nodemon --save-dev
// server.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const PORT = 4000;
const cors = require('cors');
app.use(cors());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.listen(PORT, function(){
console.log('Server is running on Port:',PORT);
});
nodemon server
Step:8 install and connect with MongoDB Database
mongod
// DB.js
module.exports = {
DB: 'mongodb://localhost:27017/mevncrud'
}
// server.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const PORT = 4000;
const cors = require('cors');
const mongoose = require('mongoose');
const config = require('./DB.js');
mongoose.Promise = global.Promise;
mongoose.connect(config.DB, { useNewUrlParser: true }).then(
() => {console.log('Database is connected') },
err => { console.log('Can not connect to the database'+ err)}
);
app.use(cors());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.listen(PORT, function(){
console.log('Server is running on Port:',PORT);
});
Step:9 Create a Mongoose Schema
// post.model.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Define collection and schema for Post
let Post = new Schema({
title: {
type: String
},
body: {
type: String
}
},{
collection: 'posts'
});
module.exports = mongoose.model('Post', Post);
Step:10 Create Routes for Node.js application
// post.model.js
const express = require('express');
const postRoutes = express.Router();
// Require Post model in our routes module
let Post = require('./post.model');
// Defined store route
postRoutes.route('/add').post(function (req, res) {
let post = new Post(req.body);
post.save()
.then(() => {
res.status(200).json({'business': 'business in added successfully'});
})
.catch(() => {
res.status(400).send("unable to save to database");
});
});
// Defined get data(index or listing) route
postRoutes.route('/').get(function (req, res) {
Post.find(function(err, posts){
if(err){
res.json(err);
}
else {
res.json(posts);
}
});
});
// Defined edit route
postRoutes.route('/edit/:id').get(function (req, res) {
let id = req.params.id;
Post.findById(id, function (err, post){
if(err) {
res.json(err);
}
res.json(post);
});
});
// Defined update route
postRoutes.route('/update/:id').post(function (req, res) {
Post.findById(req.params.id, function(err, post) {
if (!post)
res.status(404).send("data is not found");
else {
post.title = req.body.title;
post.body = req.body.body;
post.save().then(() => {
res.json('Update complete');
})
.catch(() => {
res.status(400).send("unable to update the database");
});
}
});
});
// Defined delete | remove | destroy route
postRoutes.route('/delete/:id').delete(function (req, res) {
Post.findByIdAndRemove({_id: req.params.id}, function(err){
if(err) res.json(err);
else res.json('Successfully removed');
});
});
module.exports = postRoutes;
// server.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const PORT = 4000;
const cors = require('cors');
const mongoose = require('mongoose');
const config = require('./DB.js');
const postRoute = require('./post.route');
mongoose.Promise = global.Promise;
mongoose.connect(config.DB, { useNewUrlParser: true }).then(
() => { console.log('Database is connected') },
err => { console.log('Can not connect to the database'+ err)}
);
app.use(cors());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use('/posts', postRoute);
app.listen(PORT, function(){
console.log('Server is running on Port:',PORT);
});
Step:12 Use Axios to send a network request
// main.js
import Vue from 'vue'
import App from './App.vue'
import 'bootstrap/dist/css/bootstrap.min.css'
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);
Vue.config.productionTip = false;
import HomeComponent from './components/HomeComponent.vue';
import CreateComponent from './components/CreateComponent.vue';
import IndexComponent from './components/IndexComponent.vue';
import EditComponent from './components/EditComponent.vue';
const routes = [
{
name: 'home',
path: '/',
component: HomeComponent
},
{
name: 'create',
path: '/create',
component: CreateComponent
},
{
name: 'posts',
path: '/posts',
component: IndexComponent
},
{
name: 'edit',
path: '/edit/:id',
component: EditComponent
}
];
const router = new VueRouter({ mode: 'history', routes: routes});
new Vue(Vue.util.extend({ router }, App)).$mount('#app');
// CreateComponent.vue
addPost(){
let uri = 'http://localhost:4000/posts/add';
this.axios.post(uri, this.post).then(() => {
this.$router.push({name: 'posts'});
});
}
mongo
Step:12 Display the backend data
// IndexComponent.js
<template>
<div>
<h1>Posts</h1>
<div class="row">
<div class="col-md-10"></div>
<div class="col-md-2">
<router-link :to="{ name: 'create' }" class="btn btn-primary">Create Post</router-link>
</div>
</div><br />
<table class="table table-hover">
<thead>
<tr>
<th>Title</th>
<th>Body</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="post in posts" :key="post._id">
<td>{{ post.title }}</td>
<td>{{ post.body }}</td>
<td><router-link :to="{name: 'edit', params: { id: post._id }}" class="btn btn-primary">Edit</router-link></td>
<td><button class="btn btn-danger">Delete</button></td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data() {
return {
posts: []
}
},
created() {
let uri = 'http://localhost:4000/posts';
this.axios.get(uri).then(response => {
this.posts = response.data;
});
}
}
</script>
Step:13 Send edit and update request
// EditComponent.vue
<template>
<div>
<h1>Edit Post</h1>
<form @submit.prevent="updatePost">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Title:</label>
<input type="text" class="form-control" v-model="post.title">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Body:</label>
<textarea class="form-control" v-model="post.body" rows="5"></textarea>
</div>
</div>
</div><br />
<div class="form-group">
<button class="btn btn-primary">Update</button>
</div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
post: {}
}
},
created() {
let uri = `http://localhost:4000/posts/edit/${this.$route.params.id}`;
this.axios.get(uri).then((response) => {
this.post = response.data;
});
},
methods: {
updatePost() {
let uri = `http://localhost:4000/posts/update/${this.$route.params.id}`;
this.axios.post(uri, this.post).then(() => {
this.$router.push({name: 'posts'});
});
}
}
}
</script>
Step:14 Delete the data
// IndexComponent.vue
<template>
<div>
<h1>Posts</h1>
<div class="row">
<div class="col-md-10"></div>
<div class="col-md-2">
<router-link :to="{ name: 'create' }" class="btn btn-primary">Create Post</router-link>
</div>
</div><br />
<table class="table table-hover">
<thead>
<tr>
<th>Title</th>
<th>Body</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="post in posts" :key="post._id">
<td>{{ post.title }}</td>
<td>{{ post.body }}</td>
<td><router-link :to="{name: 'edit', params: { id: post._id }}" class="btn btn-primary">Edit</router-link></td>
<td><button class="btn btn-danger" @click.prevent="deletePost(post._id)">Delete</button></td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data() {
return {
posts: []
}
},
created() {
let uri = 'http://localhost:4000/posts';
this.axios.get(uri).then(response => {
this.posts = response.data;
});
},
methods: {
deletePost(id)
{
let uri = `http://localhost:4000/posts/delete/${id}`;
this.axios.delete(uri).then(response => {
this.posts.splice(this.posts.indexOf(id), 1);
});
}
}
}
</script>
About the author
Hello, My Name is Brijpal Sharma. I am a Web Developer, Professional Blogger and Digital Marketer from India. I am the founder of Codermen. I started this blog to help web developers & bloggers by providing easy and best tutorials, articles and offers for web developers and bloggers...
Hi Brijpal, I really like your tutorial. Well done! As a complete JS, Node.js, Vue and MEVN beginner, it took me one full day to get everything running. Here are a few hints where I ran into some glitches and typos, and discovered that some things are slightly different on a Windows environment. Sharing those as a giveback to you and others trying to run your tutorial. I fear I need to split it into multiple comments due to size. This is the first part: It seems that for Windows users, it is initially safer to install Node.js and all the other stuff in one regular Windows directory, not under c:\Program Files\nodejs, which is a system directory used as the default offered by the NodeJS installer on Windows.. At least for me, I had a few strange Windows access right issues when trying to work under c:\Program Files. So I uninstalled everything, and did a fresh install under c:\Users\<MyUserID>\nodejs. On Windows, after the NodeJS install, you get on the left in the Windows menu bar, a new menu Node.js command prompt, whiich is helpful to launch as many Node command windows (called terminal on Macs). On Windows, the file names and extensions used are case sensitive, so carefully watch out to type everything correctly. For the NPM commands, it seems to be best, if not critical, to run them from a command prompt in the \c:\Program Files\nodejs directory. Otherwise, you sometimes get different effects than desired. It is a safety net, probably not always mandatory. Found a typo in a command at the beginning of the tutorial: Wrong: cd mevnexample. Correct is: cd mevnproject. (to be continued in another comment)
(continued from prior comment) After the first builds with Vue I got a blocking error message:"NoPostCSS config found". Found a solution on https://stackoverflow.com/questions/49709252/no-postcss-config-found . Created a new config File named postcss.config.js with 1 line of text, module.exports = {} , added that file to folder \\nodejs\node_modules\bootstrap\dist\CSS\ For completeness: Files App.vue and main..js should be in folder \mevnproject\src, while the 4 files for the components in folder mevnproject\src\components. At some point you use Yarn package manager (in addition to NPM), but Mongoose can be installed with the NPM command listed a line below the command for Yarn, like the other packages. It should be noted for the beginner that Yarn needs to be (optionally) installed in addition, if used. I ran into some strange build errors after first taking the Yarn install route so I uninstalled Mongoose, and reinstalled it with NPM, which still produced a build error "Cannot find module mongoose". Followed a hint on https://stackoverflow.com/questions/8623205/node-js-error-error-cannot-find-module-mongoose: In folder \mevnporject: Issue command npm link mongoose - that resolved my build error. I had to install the CORS package after some other build error, npm install cors --save, maybe CORS got separated out from Express at some point, I did not follow up further on it. It was not clear to me initially that you have to install MongoDB first locally as a Windows app on your (Windows) machine, and the Mongodb Node package is just a client of that. Got an error when building IndexComponent, at the end of its code: "Response.... is not used. Inserted some dummy code to use "response" before your code: (to be continued in another comment)
(continued from prior comment) Here is the changed code in IndexComponent: deletePost(id) { let uri = 'http://localhost:4000/posts'; this.axios.delete(uri).then(response => { var posts_temp = response.data; // to eliminate the "response is not used..." warning console.log(posts_temp); // to eliminate the "response is not used..." warning this.posts.splice(this.posts.indexOf(id), 1); }); I guess this can alternatively be solved through a specific compile setting to ignore such warnings. MongoDB: Got "Cannot connect to server [localhost:27017] on first connect" initially. Used https://stackoverflow.com/questions/41318354/mongodb-failed-to-connect-to-server-on-first-connect I installed MongoDB for Windows locally using https://www.mongodb.com/download-center/community?jmp=docs MongoDB is then automatically runnnig as a Windows service. I used MongodB Compass as a nice admin client for MongoDB. I had still some issues when trying to issue MongoDB commands from Node.JS. I used https://dangphongvanthanh.wordpress.com/2017/06/12/add-mongos-bin-folder-to-the-path-environment-variable/ to add in Windows to the Path environment variable the following install folder for MongoDB: C:\Program Files\MongoDB\Server\4.0\bin - then commands like mongod can be issued from the Node.JS environment. I got an error message from Node.JS that the default database for Mongo is not present (c:\data\db\) In a default Windows installation of MongoDB, that folder is C:\Program Files\MongoDB\Server\4.0\data (to be hopefully completed in another comment)
(continued from prior comment) With that, in Nodej.JS I entered command: mongod --dbpath=\data That finally started Mongo... See http://mongodb.github.io/node-mongodb-native/3.1/quick-start/quick-start/ for more details. After all of that, the Express server starts server.js successfully, using servemon, reports to listen to port 4000, and is connected to the database. SUCCESS!!! I'm now enjoying your tutorial running in the Chrome browser, watching the data created in MongoDB Compass. I'm now going to better understand the source code using Vue, Express, Axis, Router, Mongoose, MongoDB, and all that other new stuff introduced. THANKS A LOT for this tutorial! Michael
You must be logged in to post a comment.