This explains how we can implement a Web application built using angularjs, node js to perform create, read, update and delete operations on MongoDB database.
Web Application Architecture
The following diagram gives an overall view of our application and illustrates the various exchange between modules.
Prerequist
To better understand the next chapters, we will do a brief reminder about thinks that you should know :
1) AngularJs
AngularJS is a structural framework for dynamic web apps.
2) NodeJs
NodeJs is very powerful javascript-based framework/plateform built on Google Chrome's Javascript V8 Engine. It is used to develop I/O intensive web applications like video streaming sites, single-page applications, and other web applications.
NodeJs is a server application, is was developed by Ryan Dahl in 2009.
Environnement setup
to install NodeJs in your machine, you should download it first from nodeJs Web Site.
to make sure every think that run succeffully :
a) open your nodejs command prompt :
b) write some code :
Examples
the below examples, will help you to good understand the next chapter in wich we talk about the implementation of the server side using nodejs
.
a) Create Hello world
- create a helloworld.js file on your machine and write this code :
console.log("Hello wordl !");
- run it using node.js command prompt
b) Create Server
- create a js file named
server.js
var http = require("http");
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World\n');
}).listen(8081);
console.log('Server running at http://127.0.0.1:8081/');
- run it using node command prompt
- Make a request to nodejs server
open http://127.0.0.1:8081/ on any browser and you will get the bellow result :
c) Installing modules using npm :
- What is NPM (Node Package Manager)?
npm is bundled with Node.js installables. and its a very useful tool to provides command line utility to install nodejs modules.
npm install <Module Name>
d) Create a restfull web services :
- What is REST architecture ?
REST is web standards based architecture and uses HTTP Protocol. that allow client to access to resource in server side for modification and reading via HTTP protocol. each ressources is identified by url and global ID.
the representation of a resource returned it can be text, XML or JSON (the popular one).
1) installaing express module using npm
npm install express
this command install the famous nodejs web framework module called express.
2) create a restfull server
var express = require('express');
var app = express();
app.get('/getHWMsg', function (req, res) {
res.end('Hello World');
});
var server = app.listen(8081, function () {
console.log("Server is listening at http://127.0.0.1:8081/")
});
3) testing request
open the following url :http://127.0.0.1:8081/getHWMsg
in your browser and you will see the bellow result :
3) MongoDB
MongoDB is an sgbd oriented documents, and it does not require a predefined data schema.
MongoDB stores all documents into collections.
the representation of the stored documents is on BSON (Binary json data).
the following diagram defines how data are stored into MongoDB :
1) Environnement setup :
- download MongoDb from this link : MongoDB download
- Create target MongoDB folder, I created : C:\nodejsExample\mongoDb
- Create target MongoDB Data folder, I created : C:\nodejsExample\mongoDb\data
- Add MongoDB bin folder (you can find it in MongoDB installation folder) to the path environment variable
- create MongoDB configuration file, i created : C:\mongoDb\nodejsExample\mongod.cfg that contains the following lines :
systemLog:
destination: file
path: C:\nodejsExample\mongoDb\data\log\mongod.log
storage:
dbPath: C:\nodejsExample\mongoDb\data\db
- install the mongodb service :
the precedent command create a service with a default name : MongoDB.
- run mongodb service by tapping on command line the following command:
<span class="n">net</span> <span class="n">start</span> <span class="n">MongoDB</span>
- check the log file to view the url of your service, in my case i found : mongodb://localhost:27017/db
- Think about what development language you plan to use :
in our example we will use nodejs, so we should install mongo driver for nodejs using npm command :
npm install mongodb
To see more about MongoDB, you can follow this link.
Implementation of server side
The server will be an intermediary between client and DataBase, it will accept the HTTP requests sent by client, processes them , and return a Rest response to client (JSON or Text data).
Description of requests can be sent by client
The aim of our application is to ensure the implementation of CRUD operations , and following this logic our services will be developed.
1) getPersons
: get all available persons in database .
void
Json data composed by a list of persons.
1) addPerson
: create a new person in database .
obj : contains the data of new person to add. this argument is in json format.
status : return true, if the insert operation is successfully done, else will return false.
1) updatePerson
: create a new person in dataBase .
obj : contains new data of an existing person identified by _id
. this argument is in json format.
status : return true, if the update operation is successfully done, else will return false
2) removePerson
: remove an existing person identified by _id
from database.
id : is an integer data that refers to person identifier.
status : return true, if the delete operation is successfully done, else will return false.
Server implementation
1) include the requirement modules
var mongodb = require('mongodb');
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var url = 'mongodb://localhost:27017/db';
var express = require('express');
var app = express();
to fix the issue of : No 'Access-Control-Allow-Origin',
i add the following middleware to my NodeJS/Express app :
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS");
next();
});
var server = require('http').createServer(app);
var io = require('C:\\Users\\onasri\\AppData\\Roaming\\npm\\node_modules\\socket.io')(server);
io = io.listen(server, {log:false, origins:'*:*'});
2) implement crud methods by using Mongodb client :
var insertPerson = function(db, obj, callback) {
db.collection('persons').insertOne( obj, function(err, result) {
assert.equal(err, null);
console.log("Inserted a new person into the persons collection.");
callback();
});
};
var findPersons = function(db, callback) {
var cursor = db.collection('persons').find();
cursor.toArray(function(err, items) {
console.log(items);
callback(items);
});
};
var updatePersons = function(db, arg, callback) {
var obj = JSON.parse(arg);
var key = obj["_id"];
db.collection('persons').updateOne(
{"_id": new mongodb.ObjectID(""+key)},
{
$set: { "firstname": obj.firstname, "lastname": obj.lastname,
"adress":{"zipcode": obj.adress.zipcode, "country": obj.adress.country}}
}, function(err, results) {
console.log(results);
callback();
});
};
var removePersons = function(db, key, callback) {
db.collection('persons').deleteMany(
{ "_id": new mongodb.ObjectID(key)},
function(err, results) {
console.log(results);
callback();
}
);
};
3) implement a rest services
app.get('/getPersons', function (req, res) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
findPersons(db, function(data){ db.close(); res.end(JSON.stringify(data)); });
});
});
app.get('/addPerson', function (req, res) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
var obj = req.query.obj;
insertPerson(db, JSON.parse(obj), function(){
db.close();
res.end("true");
});
});
});
app.get('/updatePerson', function (req, res) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
var obj = req.query.obj;
updatePersons(db, obj, function(){
db.close();
res.end("true");
});
});
});
app.get('/removePerson', function (req, res) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
var key = req.query.id;
removePersons(db, key, function(){
db.close();
res.end("true");
});
});
});
4) Extra code
the below code allow to extract from a json file a list of person to populate your database.
[
{"firstname":"Nasri 0","lastname":"Omar 1","adress":{"zipcode":1,"country":"France"}},
{"firstname":"Nasri 1","lastname":"Omar 2","adress":{"zipcode":2,"country":"France"}},
{"firstname":"Nasri 2","lastname":"Omar 3","adress":{"zipcode":3,"country":"France"}}
]
- parsing and populate the database using an existing data
var fs = require("fs");
fs.readFile( "persons.json", 'utf8', function (err, data) {
persons = JSON.parse( data );
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
db.collection('persons').remove({})
db.collection('persons').drop();
db.collection('persons').insert( persons, function(err, result) {
console.log( result );
assert.equal(err, null);
console.log("Inserted many documents into persons collection.");
db.close();
});
});
});
5) create our server
server.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
});
6) start server
open nodejs command prompt and write the following code :
node CRUDnode.js
implementation of client side
I) Project tree
the client project tree is constituted by three parts :
1) Controllers folder
: contains the declaration of controllers.
2) Services folder
: has the declaration of custom services related to each controllers.
2) View
: contains html pages and a js file that contains the initialization of different module and routes.
the following picture, can more explain the organisation of our project :
II) Services
Each service created, contains a list of functions that build a request (http) which point to a specific url in server side.
these services will be called from controller to execute some specific actions.
1)
IndexServices.js
return functions that build a http request :
- getPersons : return http request that point to : http://127.0.0.1:8081/getPersons.
- addPerson : return http request that point to : http://127.0.0.1:8081/addPerson.
- editPerson : return http request that point to : http://127.0.0.1:8081/updatePerson.
- deletePerson : return http request that point to : http://127.0.0.1:8081/removePerson.
appIndex.factory('DataService', ['$http', function ($http) {
var getPersons = function () {
return $http.get("http://127.0.0.1:8081/getPersons");
}
var addPerson = function (obj) {
var data = angular.copy(obj);
var parameters = {
obj: JSON.stringify(data),
};
var config = {
params: parameters
};
return $http.get("http://127.0.0.1:8081/addPerson", config);
}
var editPerson = function (obj) {
var data = angular.copy(obj);
var parameters = {
obj: JSON.stringify(data),
};
var config = {
params: parameters
};
return $http.get("http://127.0.0.1:8081/updatePerson", config);
}
var deletePerson = function (id) {
var parameters = {
id: id,
};
var config = {
params: parameters
};
return $http.get("http://127.0.0.1:8081/removePerson", config);
}
return {
getPersons: getPersons,
addPerson: addPerson,
editPerson: editPerson,
deletePerson: deletePerson,
}
}]);
III) Controller
the aim functionalities of this controller are :
- load persons from remote database
- remove an existing person identified by
_id
- create a new person
- update an existing person using its identifier
_id
appIndex.controller('indexController', ['$scope', 'DataService', function ($scope, DataService) {
$scope.listPerson = "";
loadPersons();
function loadPersons()
{
DataService.getPersons().then(function successCallback(response) {
if (response.data.length > 0) {
$scope.listPerson = response.data;
}
}, function errorCallback(response) {
});
}
$scope.Remove = function(id) {
DataService.deletePerson(id).then(function successCallback(response) {
if (response.data == "true") {
loadPersons();
alert("succefully done !");
}
}, function errorCallback(response) {
});
}
$scope.Edit = function (elem) {
DataService.editPerson(elem).then(function successCallback(response) {
if (response.data == "true") {
loadPersons();
alert("succefully done !");
}
}, function errorCallback(response) {
});
}
$scope.AddNewPerson = function (master) {
DataService.addPerson(master).then(function successCallback(response) {
loadPersons();
$("#myModalFormAddPerson").modal("hide");
}, function errorCallback(response) {
alert(response.status);
});
}
}]);
IV) View
Code
>!DOCTYPE html>
>html>
>head>
>meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
>title>NASRI OMAR CRUD Application>/title>
>meta charset="utf-8" />
>script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js">>/script>
>link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
>script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js">>/script>
>script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js">>/script>
>script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js">>/script>
>script src="ApplicationCRUD.js">>/script>
>script src="Services/IndexServices.js">>/script>
>script src="Controllers/indexCtrl.js">>/script>
>/head>
>body ng-app="MyAppCrud" ng-controller="indexController">
>div id="wrapper">
>div class="modal fade" id="myModalFormAddPerson" role="dialog">
>div class="modal-dialog">
>div class="modal-content">
>div class="modal-header">
>button type="button" class="close" data-dismiss="modal" aria-label="Close">>span aria-hidden="true">×>/span>>/button>
>h4 class="modal-title" id="IdModalTitle"> Add New Person>/h4>
>/div>
>div class="modal-body">
>!--Formulaire-->
>form name="myform" class="form-horizontal">
>div class="form-group">
>label class="col-sm-4 control-label" required>first Name>/label>
>div class="col-sm-8">
>input type="text" ng-model="master.firstname" class="form-control" placeholder="enter first Name" ng-required="true" />
>/div>
>/div>
>div class="form-group">
>label class="col-sm-4 control-label">last Name>/label>
>div class="col-sm-8">
>input type="text" ng-model="master.lastname" class="form-control" placeholder="enter last Name" ng-required="true" />
>/div>
>/div>
>div class="form-group">
>label class="col-sm-4 control-label">Zip code>/label>
>div class="col-sm-8">
>input type="text" ng-model="master.adress.zipcode" class="form-control" placeholder="enter zip code" ng-required="true" />
>/div>
>/div>
>div class="form-group">
>label class="col-sm-4 control-label">country>/label>
>div class="col-sm-8">
>input type="text" ng-model="master.adress.country" class="form-control" placeholder="enter country" ng-required="true" />
>/div>
>/div>
>div class="modal-footer">
>button class="btn btn-default" data-dismiss="modal">Cancel>/button>
>button ng-click="myform.$valid && AddNewPerson(master)" class="btn btn-primary">Validate>/button>
>/div>
>/form>
>/div>
>/div>
>/div>
>/div>
>div class="row">
>center>>h3>Sample CRUD application using AngularJS, NodeJs and MongoDb>/h3>>/center>
>/div>
>div class="row">
>div class="col-lg-8 col-lg-offset-2">
>div class="row">
>button type="button" class="btn btn-info btn-sm" data-toggle="modal" data-target="#myModalFormAddPerson">Add Person>/button>
>/div>
>div class="row">
>table class="table table-responsive">
>thead>
>tr>>th>First Name>/th>>th>Last Name>/th>>th>Address>/th>>/tr>
>/thead>
>tbody ng-repeat="elem in listPerson">
>tr>
>td class="col-lg-2">>input type="text" ng-model="elem.firstname" />>/td>
>td class="col-lg-2">>input type="text" ng-model="elem.lastname" />>/td>
>td class="col-lg-6">Zip code : >input type="text" ng-model="elem.adress.zipcode" /> Country : >input type="text" ng-model="elem.adress.country" />>/td>
>td class="col-lg-2">>a href="#" ng-click="Edit(elem)">>span class="glyphicon glyphicon-edit">>/span> save>/a> >a href="#" ng-click="Remove(elem._id)">>span class="glyphicon glyphicon-remove">>/span> Remove>/a> >/td>
>/tr>
>/tbody>
>/table>
>/div>
>/div>
>div class="col-lg-offset-2">>/div>
>/div>
>/div>
>/body>
>/html>
V) User interface manipulation
1) Load available Persons
2) Add new Person
First, user should click on add Person button to show insertion form.
after complete form, clic on validate button to add a new person.
3) Update an existing person
user can change the attributes of a selected person and clic on associate save icon , to save changes.
4) Remove a selected person
user can select a person to delete it, and clic on remove icon :
result :