Appointment Booking using Angularjs, Nodejs, Mongodb

In this tutorial, we will create a simple, real and single page Appointment Booking web application using Javascript Fullstack or MEAN Stack (MongoDB + Express + AngualrJS + NodeJS) which can also be used as an Event Scheduler.
- The Javascript fullstack will have both Client and Server architecture and will share the same JSON (Javascript Simple Object Notation) format across Client, Server and Database.
- The code will be fast, modular and less redundant.
- We will integrate Google Material Design guidelines into our code for a better UI experience.
- We will use document based no-sql database named MongoDB
Installation
Install Required Softwares
- NodeJS (http://nodejs.org) *
'NodeJS is a non blocking, event-driven javascript framework for building network based applications. This comes with Node Package Manager. (npm)'
Install NodeJS and run node
- MongoDB (http://mongodb.org)*
"MongoDB is a Javascript based cross-platform document-oriented NoSQL database."
Install MongoDB and run mongod in a separate shell to keep an instance of the MongoDB Daemon running
Start the application Open Command Prompt / Terminal and Run the following commands
npm install : Installs all required server dependencies. bower install: Installs front-end packages required for our application. node server: Starts the application on port 8080 (http://localhost:8080)
Open your web browser and point to http://localhost:8080
Code
client/index.html The starting point for our application front end.
<html ng-app="myApp"> | |
<div ng-controller = "myCtrl"> | |
<input type = "file" file-model = "myFile"/> | |
<button ng-click = "uploadFile()">Upload File</button> | |
</div> | |
</html> | |
<script src="angular.min.js"></script> | |
<script> | |
var myApp = angular.module('myApp', []); | |
myApp.directive('fileModel', ['$parse', function ($parse) { | |
return { | |
restrict: 'A', | |
link: function(scope, element, attrs) { | |
var model = $parse(attrs.fileModel); | |
var modelSetter = model.assign; | |
element.bind('change', function(){ | |
scope.$apply(function(){ | |
modelSetter(scope, element[0].files[0]); | |
}); | |
}); | |
} | |
}; | |
}]); | |
myApp.service('fileUpload', ['$http', function ($http) { | |
this.uploadFileToUrl = function(file, uploadUrl){ | |
var fd = new FormData(); | |
fd.append('file', file); | |
$http.post(uploadUrl, fd, { | |
transformRequest: angular.identity, | |
headers: {'Content-Type': undefined} | |
}) | |
.success(function(){ | |
}) | |
.error(function(){ | |
}); | |
} | |
}]); | |
myApp.controller('myCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){ | |
$scope.uploadFile = function(){ | |
var file = $scope.myFile; | |
var uploadUrl = "/savedata"; | |
fileUpload.uploadFileToUrl(file, uploadUrl); | |
}; | |
}]); | |
</script> |
client/app.js It starts the angular module and links the required external dependencies.
'use strict'; | |
angular.module('appointmentApp', ['ngMaterial']) |
client/customer.html Appointment details with customer information.
<md-dialog aria-label="Mango (Fruit)" ng-cloak flex-lg="25" flex="50" flex-sm="100"> | |
<form ng-submit="answer(customer)"> | |
<md-toolbar> | |
<div class="md-toolbar-tools"> | |
<h2>Slot: {{customer.slot.date | date:'dd-MMM-yyyy @ h:mma'}} </h2> | |
<span flex></span> | |
<md-button class="md-icon-button" ng-click="cancel()"> | |
<md-icon md-svg-src="img/icons/ic_close_24px.svg" aria-label="Close dialog"></md-icon> | |
</md-button> | |
</div> | |
</md-toolbar> | |
<md-dialog-content> | |
<md-content layout="column" layout-align="start center"> | |
<md-input-container> | |
<label>Name</label> | |
<input ng-model="customer.name" required/> | |
</md-input-container> | |
<md-input-container> | |
<label>phone no</label> | |
<input ng-model="customer.phone" required/> | |
</md-input-container> | |
<md-input-container layout-align="center center"> | |
</md-input-container> | |
</md-content> | |
<md-dialog-actions layout="row" layout-align="center center"> | |
<md-button type="submit" class="md-raised md-warn">Book Appointment</md-button> | |
</md-dialog-actions> | |
</md-dialog-content> | |
</form> | |
</md-dialog> |
client/main.css All css files for main.html
.navbar-text { margin-left: 15px; } | |
.gray { background: #f5f5f5; } | |
.green { background: #b9f6ca; } | |
.yellow { background: #ffff8d; } | |
.blue { background: #84ffff; } | |
.darkBlue { background: #80d8ff; } | |
.deepBlue { background: #448aff; } | |
.purple { background: #b388ff; } | |
.lightPurple { background: #8c9eff; } | |
.red { background: #ff8a80; } | |
.pink { background: #ff80ab; } | |
.footer .footer-content { | |
text-align: center; | |
padding: 30px 0; | |
margin-top: 70px; | |
border-top: 1px solid #E5E5E5; | |
} |
client/main.html Application’s front end
<section layout="row"> | |
<md-content layout="row" flex="66" layout-wrap> | |
<md-card ng-repeat="d in $ctrl.dates" ng-class="$ctrl.getColor($index)" class="md-whiteframe-z2" flex flex-sm="40" flex-xs="100"> | |
<md-card-content> | |
<h2>{{d.k | date:'dd-MMM-yyyy'}}</h2> | |
<p layout="column"> | |
<md-button class="md-primary md-raised" | |
ng-repeat="i in d.v" | |
ng-click="$ctrl.showAdvanced(i)" | |
ng-disabled="!i.active" | |
flex> | |
{{i.date | date:'h:mma'}} | |
</md-button> | |
</p> | |
</md-card-content> | |
<md-card-footer></md-card-footer> | |
</md-card> | |
</md-content> | |
<md-card class="md-whiteframe-z2" flex="33"> | |
<md-card-content> | |
<h2>Booked Appointments</h2> | |
<p layout="column" ng-repeat="a in $ctrl.appointments"> | |
{{a.name}} ({{a.phone}}) => {{a.date | date:'dd-MMM-yyyy @ h:mma'}} | |
</p> | |
</md-card-content> | |
<md-card-footer></md-card-footer> | |
</md-card> | |
</section> |
client/main.js It implements required logics.
'use strict'; | |
(function() { | |
class MainController { | |
constructor($http,$mdMedia,$mdDialog) { | |
this.message = 'Hello'; | |
this.$http=$http; | |
this.appointment = []; | |
this.slots = []; | |
this.$mdMedia = $mdMedia; | |
this.$mdDialog = $mdDialog; | |
// Configure dates | |
var today = new Date(); | |
var dd = today.getDate(); | |
var mm = today.getMonth()+1; //January is 0! | |
var yyyy = today.getFullYear(); | |
if(dd<10) { | |
dd='0'+dd | |
} | |
if(mm<10) { | |
mm='0'+mm | |
} | |
// Create date and slots array | |
this.days = [{dd:dd,mm:mm,yyyy:yyyy},{dd:dd+1,mm:mm,yyyy:yyyy},{dd:dd+2,mm:mm,yyyy:yyyy},{dd:dd+3,mm:mm,yyyy:yyyy}]; | |
this.slots= [{h:'10',m:'00'},{h:'10',m:'15'},{h:'10',m:'30'},{h:'10',m:'45'},{h:'11',m:'00'},{h:'11',m:'15'},{h:'11',m:'30'}]; | |
} | |
save(appointment){ | |
appointment.active=true; | |
this.$http.post('/api/appointments',appointment).then(res=>{ | |
this.dates = this.allot(this.slots,this.days,this.appointments); | |
this.$http.get('/api/appointments').then(response=>{ | |
this.appointments=response.data; | |
this.dates = this.allot(this.slots,this.days,this.appointments); | |
}); | |
}); | |
} | |
$onInit(){ | |
var vm = this; | |
this.$http.get('/api/appointments').then(response=>{ | |
this.appointments=response.data; | |
this.dates = this.allot(this.slots,this.days,this.appointments); | |
}); | |
} | |
delete(d){ | |
this.$http.delete('/api/appointments/'+d._id); | |
} | |
allot(slots, days, appointments){ | |
var a = []; | |
_.each(days, function(d) { | |
var k=new Date(d.yyyy,d.mm,d.dd); | |
var v = []; | |
_.each(slots, function(s) { | |
var x = new Date(d.yyyy,d.mm,d.dd,s.h,s.m); | |
var mx = moment(x); | |
var active = true; | |
_.each(appointments, function(g) { | |
var sdt = moment(new Date(g.date)); | |
if(moment.duration(sdt.diff(mx))._milliseconds===0){ | |
active = false; | |
} | |
}) | |
v.push({date:x,active:active}); | |
}) | |
a.push({k:k,v:v}); | |
}) | |
return a; | |
} | |
showAdvanced(slot) { | |
var vm = this; | |
var useFullScreen = (this.$mdMedia('sm') || this.$mdMedia('xs')) && this.customFullscreen; | |
this.$mdDialog.show({ | |
controller: function($scope,$mdDialog,slot){ | |
$scope.customer = {}; | |
$scope.customer.slot = slot; | |
$scope.answer = function(answer){ | |
$mdDialog.hide(answer); | |
}; | |
}, | |
templateUrl: 'app/customer.html', | |
locals : { | |
slot : slot | |
}, | |
clickOutsideToClose:true, | |
fullscreen: useFullScreen | |
}) | |
.then(function(answer) { | |
answer.date = answer.slot.date; | |
vm.save(answer); | |
}); | |
} | |
getColor($index) { | |
var _d = ($index + 1) % 11; | |
var bg = ''; | |
switch(_d) { | |
case 1: bg = 'green'; break; | |
case 2: bg = 'darkBlue'; break; | |
case 3: bg = 'blue'; break; | |
case 4: bg = 'yellow'; break; | |
case 5: bg = 'pink'; break; | |
case 6: bg = 'darkBlue'; break; | |
case 7: bg = 'purple'; break; | |
case 8: bg = 'deepBlue'; break; | |
case 9: bg = 'lightPurple'; break; | |
case 10: bg = 'red'; break; | |
default: bg = 'yellow'; break; | |
} | |
return bg; | |
} | |
} | |
angular.module('appointmentApp') | |
.component('main', { | |
templateUrl: 'app/main.html', | |
controller: MainController | |
}); | |
})(); |
server/index.js It creates the appointments ReST API routes.
// Dependencies | |
var express = require('express'); | |
var mongoose = require('mongoose'); | |
var bodyParser = require('body-parser'); | |
// MongoDB | |
mongoose.connect('mongodb://localhost/appointment'); | |
// mongoose.connection.on('error', function(){}); | |
// Express | |
var app = express(); | |
app.use(express.static(__dirname + './../public')); | |
app.use(bodyParser.json()); | |
app.use(bodyParser.urlencoded({ extended: true })); | |
// Routes | |
app.use('/api', require('./api/appointment/')); | |
// Start server | |
var port = 8080 | |
, ip = "127.0.0.1"; | |
app.listen(port, ip, function() { | |
console.log('Express server listening on %d', port); | |
}); |
server/api/appointment/index.js The appointments ReST API routes are defined here.
// Dependencies | |
var express = require('express'); | |
var router = express.Router(); | |
//Product | |
var Appointment = require('./model'); | |
Appointment.methods(['get', 'put', 'post', 'delete']); | |
Appointment.register(router, '/appointments'); | |
// Return router | |
module.exports = router; |
server/api/appointment/model.js Defines the appointments database model.
// Dependencies | |
var restful = require('node-restful'); | |
var mongoose = restful.mongoose; | |
// Schema | |
var appointmentSchema = new mongoose.Schema({ | |
date: Date, | |
name: String, | |
phone: String, | |
status: Boolean | |
}); | |
// Return model | |
module.exports = restful.model('Appointments', appointmentSchema); |
package.json It carries node dependencies which are required for this application.
{ | |
"name": "appointments", | |
"version": "1.0.0", | |
"description": "Appointments using AngularJS, NodeJS and MongoDB (Javascript Fullstack)", | |
"dependencies": { | |
"body-parser": "^1.14.2", | |
"express": "^4.13.4", | |
"mongoose": "^4.1.3", | |
"node-restful": "^0.2.2" | |
}, | |
"devDependencies": {}, | |
"scripts": { | |
"start": "node server" | |
}, | |
"repository": { | |
"type": "git", | |
"url": "git+https://github.com/itswadesh/simple-appointment.git" | |
}, | |
"author": "Swadesh Behera", | |
"license": "ISC", | |
"bugs": { | |
"url": "https://github.com/itswadesh/simple-appointment/issues" | |
}, | |
"homepage": "https://github.com/itswadesh/simple-appointment#readme" | |
} |

Most Popular Posts
- ShopNx - The assistant manager for influencers
- Frontendfun marketplace for software projects
- Complete steps to configure elasticsearch on Ubuntu
- Configure Vultr for Nodejs Deployment
- Appointment Booking Microservice using Javascript Fullstack
- 100+ most effective ways to promote a new blog for free
- Steps to Configure Digital Ocean Droplet for Nodejs Application Deployment
- Appointment Booking using Angularjs, Nodejs, Mongodb
- Send email with PDF attachment using PHP
- Simple task manager application using Angularjs PHP Mysql
- Steps to Configure Amazon EC2 for Nodejs app deployment
- Inventory Manager Using Angularjs Mysql Php
- User authentication using Angularjs, PHP, Mysql
- Demo of a simple CRUD Restful php service used with Angularjs and Mysql
- Simple file upload example using Angularjs
- Generate PDF using PHP from Mysql database
- Creating REST API using Nodejs and consuming in Angularjs
- Simple project demonstrates how to send email using Nodejs
- Voting system similar to stackoverflow using Angularjs PHP and Mysql
- Angularjs datagrid paging, sorting, filter using PHP and Mysql
- Useful database helper class to generate CRUD statements using PHP and Mysql
- Online Shopping Mega Menu using Angularjs, PHP, Mysql
- How to create a facebook style autocomplete using Angularjs
- Steps configuring PHP Cron Jobs - Godaddy
- How to change Mysql password
- A simple Angularjs web app that converts text to url format
- Creating SWAP file on Linux