Friday, September 2, 2016

Deploying the notes app with Cloud9

As a follow-up to this previous post, where we built a simple fullstack JavaScript app with MEAN, we now use Cloud9 to deploy our app in the cloud.

How to deploy MEAN with c9

First you need to setup an account. Then you get the workspace. Setup your workspace, then click Run and you're ready to go.

Create a workspace

1. Go to https://c9.io
2. Log in with your GitHub account → you will see all your repositories
3. Clone a repository (e.g. notes) to a new workspace. Choose Node.js as Workspace type.

*If cloning a repository you don't own doesn't work, then fork it and clone your fork

Setup the workspace

When you clone the repository, your workspace is created. You get a fully working Ubuntu system in the cloud. Now you can "deploy" your Notes app in the cloud. There are a few things to do before this is possible:

1. Install MongoDB by simply running the following in the command line:

sudo apt-get install -y mongodb-org

After installing, make sure to run these additional commands:

mkdir data
echo 'mongod --bind_ip=$IP --dbpath=data --nojournal --rest "$@"' > mongod
chmod a+x mongod

Then run the mongod script:

./mongod

The above is necessary due to some c9 restrictions. See this post for more information.

2. Install bower

sudo npm install -g bower

3. Now run

npm install

4. Your main server file must include the follwing:

// setup defaults if existing
process.env.PORT = process.env.PORT || 1337;
process.env.IP = process.env.IP || 'localhost';

// start server
app.listen(process.env.PORT, process.env.IP, function () {
 console.log("Server started at " + new Date())
});

If everything went well, then open a new chrome tab and type https://[app-name]-[user-name].c9users.io . For instance, deploying the notes app on my account makes it available under the following link: https://notes-roby-rodriguez.c9users.io

For a working notes workspace check out this link.

Troubleshooting

Frequently, your c9 workspace will get passivated, this meaning it's placed into a standby state after a while (since your account is free). In this case you might encounter a crash with MongoDB. On workspace activation, if the driver refuses to connect, try running the following commands:

rm data/mongod.lock
mongod --dbpath data --repair

Then run the mongod script again.

Tuesday, August 30, 2016

Building a simple notes app with MEAN

This is a step-by-step presentation of how to build an initially simple web app using the fullstack JavaScript solution provided by MEAN. We will start off with something very basic and then try to add new features and improvements on the way.

Why choose MEAN?

First of all, MEAN stands for Mongo-Express-Angular-Node and it's a combination of JavaScript frameworks and APIs that help building web apps. One of its main advantages is that it allows fast development and offers loads of options in what regards tools, plugins, third-party libraries etc. I will not dive deep into explaining what it is or whether you should use it or not, as there's already plenty of material for that on the internet. I've already been convinced of its usefulness and I'll try as much as possible to share some of my experiences in this tutorial.

1. Getting Started

The notes app that we are going to build is very similar to Google Keep. It basically allows you to add a note that might sum up an idea, a to-do, a reminder or any kind of other information. The app allows you to label/group your notes and it also features the possibility of searching through your notes. Later on we will see how we can personalize it by adding user authentication and other neat features.

1.1 Preparation

Firstly, you should have a basic understanding of JavaScript. But don't worry very much about that right now, as most of this stuff will be pretty straight-forward. Secondly, you'll have to choose your development tools. I personally use Ubuntu 14.04 and Webstorm 10, but feel free to choose anything you like, as MEAN.js is available on most platforms and there are plenty of other IDEs that allow support for it.
Among the requirements before starting development would be the following:
  • git - download and install it as the code for this tutorial is available on GitHub and you might need it if you stumble on your way
  • Node.js and MongoDB - these is your BE (backend) - node will be your web-server and mongo is the database
*As a side-note, when you install Node.js you also install npm (Node package manager) which is used to download libraries and manage dependencies. Given that npm manages your BE, a similar build tool named Bower will be used to manage your FE (frontend).
Follow the steps and install the up-mentioned requirements. When you're ready make sure you've done it right, open a terminal and enter:

npm

This should output something like:


which tells node/npm has been installed. You could then also check if MongoDB is ready to go:

status mongod

This would output something like:


1.2 File → New Project..

If everything went well, open Webstorm and start a new project. Choose the first option ("empty project") since it's better to start from scratch in the beginning. Later on when you get to feel more confident you can use generators. Name your new project as you wish and then add the following files and folders to obtain the following structure:













As far as I've seen this is the layout most projects will follow. It has the following meaning:
  • app - this directory contains your BE sources
  • public - here's where you place all your FE sources (JavaScript files, CSS, images, icons etc.)
  • .gitignore - when using Git not all sources need to be checked into source control, so it's best to leave out some files (e.g. generated files, downloaded modules, configuration files etc.). If you don't know what to include here, take a look at the one I've checked in for this project.
  • bower.json - this is a JSON file that lists all your FE dependencies
  • package.json - similar to the previous, here you list your BE dependencies 
  • README - it's good practice to document your projects (and of course your sources) and if you wish you may also include a license file if you're working on something really important
  • server.js - by convention, this file will be used to launch your BE - it's where all the magic happens as we will see later
Now if you're rather lazy you can grab the commit with the empty project from GitHub. Open Webstorm and then go to VCS → Checkout from Version Control. Enter your GitHub credentials and then you should reach something like:

Then, you can easily grab a commit (like this one) by entering:

git reset --hard fb58046d8b8726f614198a40af1c99f66ae26659

*As a side note, if you ever wish to put some project of yours on GitHub, it's really easy with Webstorm. Go to VCS → Import into Version Control → Share project on GitHub. Enter your login credentials, then add a new repository and click Share. You will be prompted with a dialog with your initial commit, click Ok and then your project should be public on GitHub.

2. The notes app

The app itself revolves around the "note" entity. In the first part we will learn how to build a REST API with Express.JS which is very much like an application server. The API we expose allows the client side to execute CRUD operations on the this entity. We will se how we can interact with MongoDB and how we can deal with error handling. The second part will show how we can use Angular.JS and Bootstrap to interact with the server side and build up the presentation layer.

2.1 The Backend

Our REST API will be a back and forth between router, controller and model. The router defines the API endpoints (URL paths) and links them to the controller methods. The controller is the place where we can put our business logic. In our case we just query the model. The model defines our schema.
Later on, we will make use of the $http module in Angular to call this API from the frontend.










For the purpose of this app we could simply structure our sources into three directories:
  • model
  • controller
  • route
Later, when dealing with a larger number of entities, we could organize them in modules, each having this basic structure.

2.1.1 The Model

Before we start developing the backend we define our entities. We will do this by using mongoose, which is a higher level framework for working with MongoDB. We could've just as easily used the native Node.js driver, but the advantage of using mongoose would be that it makes it easier to write simple things (such as CRUD) and allows faster development. More on this here.
Our first entity "note" will be defined as app/model/note.js:

// import necessary module(s)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

// define a schema
var noteSchema = new Schema({
    title: String,
    content: { type: String, required: true },
    created: Date,
    updated: Date
});

// create a model using the defined schema
var Note = mongoose.model('Note', noteSchema);

// export this to other modules
module.exports = Note;

We simply define the  entity using a mongoose schema and then expose it to the other modules. You can find the commit for this here.

2.1.2 The Controller

When dealing with REST services we focus on two objects: request and response. The Express.js framework provides a great foundation for building functionality such as pre/post-processing called middleware. The controller is a good place to gather your business logic. Here you can access the model and add your custom middleware. (e.g. validations, logging etc.)

var Note = require('../model/note');

var Controller = {};

Controller.create = function (req, res) {
    var note = new Note(req.body);

    note.save(function (err, saved) {
        if (err) {
            res.status(400);
            res.json({ error: "Error creating " + note.toString(), message: err.toString() });
        } else {
            res.status(201);
            res.json(saved);
        }
    });
};

Controller.read = function (req, res) {
    Note.find(req.params, function (err, found) {
        if (err) {
            res.status(400);
            res.json({ error: "Error finding " + found.toString(), message: err.toString() });
        } else {
            res.status(200);
            res.json(found);
        }
    });
};

Controller.update = function (req, res) {
    var query = { _id: req.params.id };

    Note.findOneAndUpdate(query, req.body, { new: true },function (err, found) {
        if (err) {
            res.status(400);
            res.json({ error: "Error updating " + found.toString(), message: err.toString() });
        } else {
            res.status(200);
            res.json(found);
        }
    });
};

Controller.delete = function (req, res) {
    var query = { _id: req.params.id };

    Note.remove(query, function (err, found) {
        if (err) {
            res.status(400);
            res.json({ error: "Error deleting " + found.toString(), message: err.toString() });
        } else {
            res.status(200);
            res.end();
        }
    });
};

module.exports = Controller;

As you may notice, the Note controller simply makes use of the CRUD functionality exposed by our mongoose model. Everything happens asynchronously, so we use callbacks to deal with "incoming" results. Upon receiving a result we send a status code and the result as a JSON object.

2.1.3 The Router

The role of the router is to delegate requests to the corresponding controller handler.

var express         = require('express');
var NoteController  = require('../controller/note-ctrl');
var router          = express.Router();

router
    .post('/note/create', NoteController.create)
    .get('/note/read/:title', NoteController.read)
    .get('/note/read/:title/:content', NoteController.read)
    .put('/note/update/:id', NoteController.update)
    .delete('/note/delete/:id', NoteController.delete);

module.exports = router;

You may notice the get and delete requests contain a ":param" in the URL. This acts like a placeholder for data you can send in the query string. You can then find these parameters in the request.params object. Alternately, when using a body, you may access it through request.body.

2.1.4 The main file

At this point we're ready to launch our fully functional REST API. We only need to configure and launch an express server. For this we will add the following to our server.js file:

// setup modules
var express         = require('express');
var bodyParser      = require('body-parser');
var mongoose        = require('mongoose');
// setup express
var app             = express();

// use middleware to parse application/json
app.use(bodyParser.json());
// use custom router
app.use('/', require('./app/route/note-rt'));
// start mongo
mongoose.connect('mongodb://localhost/notes', function (err) {
    if (err) console.error('Could not start database: ' + err.toString())
    else console.log("Database started at " + new Date())
});

// start server
app.listen(1337, 'localhost', function () {
    console.log("Server started at " + new Date())
});

I find it's best to keep things simple, so later on we could move the Express configuration code into a separate tree structure under an app/config directory.
The package.json file was previously mentioned. All your external library dependencies will be listed here. You can specify development and release dependencies as well as scripts to execute. You can find a very basic package.json in this commit. Before launching the server you need to enter the following command line:

npm install

This creates a node_modules directory where all your required libraries will be held.

2.1.5 Testing with Postman

First we need to launch the server by right clicking server.js and choosing Run/Debug, by case. You can also do this by command line, this is actually the equivallent of running

node server.js

We can now (manually) test our backend. We do this by using Postman. Alternately you could use the built-in Webstorm client: Tools → Test RESTful Web Service.
Test adding a note:
*when adding a body to your request you need to add a "Content-Type": "application/json" header

We then retrieve the note:

which yields

Updating a note:
gives:

And finally removing it:
giving:

Here are the commits for create, read, update and delete.

There are cases in which resources might not be found due to various reasons. You can cover this case by using a middleware placed right after all your custom routes. An updated server.js may be found in this commit. I've also added a logger that helps out on desplaying all client requests.

2.2 The Frontend

The Angular approach in building the frontend is to enhance the html by adding custom tags, attributes etc. making it dynamic. Angular is a lot to talk about as it is complex and it can be complicated, so here are some ideas to start with:

  • We can use templates to group/reuse html and views to present/manipulate data
  • We associate a controller to each view
  • We share data between views/controllers by using factories
  • We call services to use backend APIs
  • We use directives for custom components

We will build our frontend using Angular and design it as a SPA. At this point you can start off very simple and do everything yourself (which may take some extra time) or choose an easier way (like I did) and grab a Bootstrap template and then integrate it with Angular. For the purpose of this notes app I picked this particular theme since it's best suited for our needs.

2.2.1 Adapting the Hydrogen SPA to Angular.js

The hydrogen theme may seem cool but if we want it to "play nice" with Angular, we'll need to make a few adjustments. For those of you who don't really care what it took to make it Angular-ready, you can skip to the next subchapter directly.
When working with such templates, among the first things to do is to gather up all the original's resources (CSS, JS, fonts etc.)  and track them such that you can use them as Bower dependencies. This will make your life much easier and as a plus, you won't need to overload your GitHub repository with stuff that already exists somewhere else. For the hydrogen template, a working bower.json would look like this:

{
  "name": "notes",
  "version": "0.0.1",
  "authors": [
    "RobyRodriguez"
  ],
  "dependencies": {
    "angular": "~1.5.7",
    "angular-route": "~1.5.7",
    "bootstrap": "~3.3.6",
    "font-awesome": "~4.6.3",
    "animate.css": "~3.5.1",
    "modernizr": "~3.3.1",
    "jquery.easing": "~1.3.1",
    "waypoints": "~4.0.0",
    "magnific-popup": "~0.9.9",
    "salvattore": "~1.0.9"
  }
}

This way, when running a "bower install" you will have all these frontend libararies gathered up in your bower_components directory from which you can then serve to your client.
Some of the stuff you will not find, in our case hydrogen's CSS which lies in css/style.css. A good idea is to place your own custom CSS separately, in a file such as css/style_extra.css. After integrating this theme, your project structure would now contain the following additions:


The entry point of the frontend is index.html. This is where you place all your styling and necessary libraries references. As a general rule, stylesheets are placed in the <head> tag such that they are loaded first, since this is the first content you see when the page is loaded. At the end of your <body> tag you will put your JavaScript references.

When using Angular you should add the following inside the <body> of your index.html:
<div ng-app="notesApp">
    <ng-view></ng-view>
</div>

This identifies the use of "notesApp" module which basically represents your Angular app. The other important tag used here is ng-view, which will act as a placeholder for the different views you use in your app. But more on this later. The last thing you need here is a place to bootstrap your Angular app. In our case this is the js/app.js file which looks like this initially:

angular.module("notesApp", []);

You can find the commit for this subchapter here.

2.2.2 Adding a note

In the previous section we only managed to build the structure of our website but didn't really accomplish much visually. If you type http://localhost:1337 you just will get a blank page (with hopefully no console errors).
So we set out with adding a new note. We will add a new view ./public/views/create.html with a form that allows doing so. This should look much like:

<form ng-submit="create()">
    <div class="row">
        <div class="col-md-12">
            <div class="form-group">
                <input type="text" class="form-control" placeholder="Enter title..." ng-model="note.title">
            </div>
            <div class="form-group">
                <input type="text" class="form-control" placeholder="Enter (optional) image URL..." ng-model="note.image">
            </div>
            <div class="form-group">
                <textarea class="form-control" cols="30" rows="10" placeholder="Enter content..." ng-model="note.content"></textarea>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Add">
            </div>
        </div>
    </div>
</form>

You might have noticed the ng-* attributes. These are the ones which allow binding logic to this view. So the next thing to do is to write a controller that defines this logic.

angular.module('notesApp')
    .controller('CreateController', function($scope, $rootScope, $location, NoteService) {
        $scope.note = {};
        $scope.create = function () {
            NoteService.createNote($scope.note, function (err, res) {
                if (err) {
                    $rootScope.error = 'Could not create note';
                    $rootScope.errorMessage = JSON.stringify(err);
                } else {
                    $rootScope.infoMessage = 'Added note: ' + JSON.stringify(res);
                    $location.path('/home');
                }
            });
        };
});

As we see, the note variable, as well as the create method are placed on our create controller's scope. The note defaults to an empty object upon controller initialization whereas the create method calls a "note-" service, passing the same note object which will then contain user data.

angular.module('notesApp')
    .service('NoteService', function($http) {
        this.createNote = function (data, next) {
            return $http.post('/note/create', data)
                .success(function(info){
                    next(null, info);
                })
                .error(function (err) {
                    next(err);
                });
        };
});

The service makes a POST to our API endpoint. We can use a Node-like "next" callback to pass data back to our controller.
You might have noticed the use of the "root scope" in our create controller. When dealing with server responses it may be a good idea to give some input to the user regarding the result of the current operation (success/fail). As a homework, you could write up a new controller that does that. (hint: write a reusable template that holds each "error", "errorMessage" and "infoMessage")

Finally, we establish a new route for the create action. We will use the route provider module to define it:

angular.module("notesApp", [
    'ngRoute'
]).config(function ($routeProvider) {
    $routeProvider
        .when('/create', {
            templateUrl: 'views/create.html',
            controller: 'CreateController'
        });
});

Now you can enter http://localhost:1337/#/create in your favorite browser and you should be able to complete the new form:

We can look up the result of this operation by entering db.notes.find() in the mongo shell. Its output should look like:

You can find the full commit for this section here.

2.2.3 Reading notes

Before we start reading notes it might be a good idea to add a few to our database. So, as a homework, you should write a script that builds the notes database each time you run it. As a hint, you could use the data from hydrogen's index.html to build a JSON and dump it into the database. If you need help, take a look at this commit.

Now that we have something to show we will add a new read method to our notes service:

angular.module('notesApp')
    .service('NoteService', function($http) {
        ...
        this.readNotes = function (next) {
            return $http.get('/note/read')
                .success(function(notes){
                    next(null, notes);
                })
                .error(function (err) {
                    next(err);
                });
        };
});

And then we will create a factory that stores the notes retrieved by calling the service. As a reminder, we generally use these factories when we need to share data between controllers.

angular.module('notesApp')
    .factory('NotesFactory', function(NoteService) {
        var notes = [];

        return {
            getNotes: function(next) {
                if (next) {
                    NoteService.readNotes(function (err, res) {
                        notes = res;
                        next(err, res)
                    })
                }
                return notes;
            }
        };
    });

We will add a new "home-" view and controller that will also be the default page the user sees. The home controller loads the notes on its scope upon initialization:

angular.module('notesApp')
    .controller('HomeController', function($scope, $rootScope, NotesFactory) {

        $scope.loadNotes = function () {
            // load user notes
            NotesFactory.getNotes(function (err, res) {
                if (err) {
                    $rootScope.error = 'Could not load notes';
                    $rootScope.errorMessage = JSON.stringify(err);
                } else {
                    $scope.notes = res;
                }
            });
        };

        $scope.loadNotes();
});

In order to display the notes we will use the ng-repeat directive. So we add a new view 'views/home.html':

<div ng-include src="'templates/serverResponse.html'"></div>
<div id="fh5co-main" >
    <div class="container">
        <div class="row">
            <div id="fh5co-board">
                <div ng-repeat="note in notes track by $index">
                    <div class="item">
                        <div class="animate-box" style="opacity: inherit;">
                            <a href="#{{ 'nt-viewer-' + $index }}" class="image-popup fh5co-board-img">
                                <img ng-src="{{ note.image }}">
                                <div id="{{ 'nt-viewer-' + $index }}" class="note-viewer mfp-hide">
                                </div>
                            </a>
                        </div>
                        <div class="fh5co-item-title">{{ note.title }}</div>
                        <div class="fh5co-desc">{{ note.content }}</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Finally, we add the new route to app.js:

...
.when('/home', {
   templateUrl: 'views/home.html',
   controller: 'HomeController',
   controllerAs: 'hm'
})
...

The commit for displaying the notes is here.

You might have noticed the hydrogen animations are missing. No worry because we will integrate them step-by-step into our Angular app. We will start with waypoints. In order for this to work, we will refactor the original initialization function into an Angular directive. As for salvattore, it will be necessary to postpone its launch until the home controller is done loading its notes. The code for the waypoints directive should look like:

angular.module('notesApp')
    .directive('waypoint', function () {
        return {
            link: function (scope, element) {
                $(element).waypoint( function( direction ) {

                    if( direction === 'down' && !$(this).hasClass('animated') ) {
                        $(this.element).addClass('bounceIn animated');
                    }

                } , { offset: '75%' } );
            }
        };
    });

As for salvattore, we will add an init-method in main.js to call in our home controller:

    ...
    return {
        initHome: function () {
            // this hack is needed to get allow angular finish its housekeeping
            setTimeout(window.salvattore.init, 0);
        }
    }
    ...

For more information on why the above call is needed check this source. You can find the commit for the above here.

2.2.4 Updating a note

For updating notes we could easily use the existing hydrogen popup. The only thing we need to do is write a new directive to integrate it into our Angular app:

angular.module('notesApp')
    .directive('magnificPopup', function () {
        return {
            link: function (scope, element) {
                $(element).magnificPopup({
                    type: 'inline',
                    removalDelay: 300,
                    mainClass: 'mfp-with-zoom',
                    ...

As you see, it contains hydrogen's original initialization code of magnific-popup. We then apply this directive to the <a> link in home.html. This will launch the popup when clicking the note image. We could then use this popup to build a form that allows editing/removing a note.

To go a step further, we will write a new factory that allows sharing the selected note with the new editor view:

angular.module('notesApp')
    .factory('NoteViewerFactory', function() {
        var note = {};

        return {
            setNote: function(data) {
                note = data;
            },
            getNote: function() {
                return note;
            }
        };
});

To make this work we need to adjust the home view:

...
<a href="#{{ 'nt-viewer-' + $index }}" ng-click="setSelection(note)" class="image-popup fh5co-board-img" magnific-popup>
...

and its corresponding controller:

angular.module('notesApp')
    .controller('HomeController', function($scope, $rootScope, $window, NotesFactory, NoteViewerFactory) {

        $scope.setSelection = function (note) {
            NoteViewerFactory.setNote(note)
        };
        ...

The next step would be to create a new template 'templates/noteViewer.html' which will contain the previously mentioned form:

<div ng-include src="'templates/serverResponse.html'"></div>
<div class="container" ng-controller="NoteViewerController">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h2>Note viewer</h2>
            <div class="fh5co-spacer fh5co-spacer-sm"></div>
            <form ng-submit="update()">
                <div class="row">
                    <div class="col-md-12">
                        <div class="form-group">
                            <input type="text" class="form-control" placeholder="Enter title..." ng-model="note.title">
                        </div>
                        <div class="form-group">
                            <input type="text" class="form-control" placeholder="Enter (optional) image URL..." ng-model="note.image">
                        </div>
                        <div class="form-group">
                            <textarea class="form-control" cols="30" rows="10" placeholder="Enter content..." ng-model="note.content"></textarea>
                        </div>
                        <div class="form-group">
                            <button type="submit" class="btn btn-primary">
                                <i class="icon-save"></i> Update
                            </button>
                            <button type="button" ng-click="delete()" class="btn btn-danger">
                                <i class="icon-trash"></i> Delete
                            </button>
                        </div>
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>

The note viewer controller:

angular.module('notesApp')
    .controller('NoteViewerController', function($scope, $rootScope, $route, NoteViewerFactory, NotesFactory, NoteService) {
        $scope.update = function () {
            var selected = NoteViewerFactory.getNote();
            NoteService.updateNote(selected._id, selected, function (err, res) {
                if (err) {
                    $rootScope.error = 'Could not update note';
                    $rootScope.errorMessage = JSON.stringify(err);
                } else {
                    $rootScope.infoMessage = 'Updated note: ' + JSON.stringify(res);
                    $.magnificPopup.instance.close();
                }
            });
        };
});

And finally, the update note service method:

angular.module('notesApp')
    .service('NoteService', function($http) {
        ...
        this.updateNote = function (noteId, data, next) {
            return $http.put('/note/update/' + noteId, data)
                .success(function(info){
                    next(null, info);
                })
                .error(function (err) {
                    next(err);
                });
        };
});

As a result of the above, when clicking a note image, the following popup should appear:

which should allow live-editing of the selected note.
You can find the commit for this section here.

2.2.5 Deleting a note

For deleting a note we will add an extra button to the editor view:

<button type="button" ng-click="delete()" class="btn btn-danger">
    <i class="icon-trash"></i> Delete
</button>

Which will render to:

Similar to update, we add a new delete method to the note viewer controller:

$scope.delete = function() {
    var selected = NoteViewerFactory.getNote();
    NoteService.deleteNote(selected._id, function(err) {
        if (err) {
            $rootScope.error = 'Could not delete note';
            $rootScope.errorMessage = JSON.stringify(err);
        } else {
            $rootScope.infoMessage = 'Deleted note: ' + JSON.stringify(selected);
            $route.reload();
            $.magnificPopup.instance.close();
        }
    });
};

And the coresponding service call:

angular.module('notesApp')
    .service('NoteService', function($http) {
        ...
        this.deleteNote = function (noteId, next) {
            return $http.delete('/note/delete/' + noteId)
                .success(function(info){
                    next(null, info);
                })
                .error(function (err) {
                    next(err);
                });
        };
});

The result of deleting a note should look like:

The commit for this section is available here.

2.2.6 Header, footer and fold-menu

The original hydrogen template also contained some headers and a fold menu. We will also integrate these into our Angular app. This will be pretty much straight-forward, as we write templates for each. The header:

<header id="fh5co-header" role="banner" ng-controller="HeaderController">
    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <a class="fh5co-menu-btn js-fh5co-menu-btn">Menu <i class="icon-menu"></i></a>
                <a class="navbar-brand" href="#/home">Notes</a>
            </div>
        </div>
    </div>
</header>

The footer:

<footer id="fh5co-footer">
    <div class="container">
        <div class="row row-padded">
            <div class="col-md-12 text-center">
                <p class="fh5co-social-icons">
                    <a href="#"><i class="icon-twitter"></i></a>
                    <a href="#"><i class="icon-facebook"></i></a>
                    <a href="#"><i class="icon-instagram"></i></a>
                    <a href="#"><i class="icon-dribbble"></i></a>
                    <a href="#"><i class="icon-youtube"></i></a>
                </p>
                <p><small>&copy; Hydrogen Free HTML5 Template. All Rights Reserved. <br>Designed by: <a href="http://freehtml5.co/" target="_blank">FREEHTML5.co</a></small></p>
            </div>
        </div>
    </div>
</footer>

And the fold menu:

<div id="fh5co-offcanvass" ng-controller="FoldMenuController">
    <a class="fh5co-offcanvass-close">Menu <i class="icon-cross js-fh5co-offcanvass-close"></i> </a>
    <h1 class="fh5co-logo"><a class="navbar-brand" href="index.html">Notes</a></h1>
    <ul class="fh5co-fold-menu">
        <li ng-class="{active: isActive('/home')}"><a href="#/home">Home</a></li>
        <li ng-class="{active: isActive('/create')}"><a href="#/create">Create</a></li>
    </ul>
    <h3 class="fh5co-lead">Connect with us</h3>
    <p class="fh5co-social-icons">
        <a href="#"><i class="icon-twitter"></i></a>
        <a href="#"><i class="icon-facebook"></i></a>
        <a href="#"><i class="icon-instagram"></i></a>
        <a href="#"><i class="icon-dribbble"></i></a>
        <a href="#"><i class="icon-youtube"></i></a>
    </p>
</div>

We also refactor the original fold-menu functionality into the main.js module and call the necessary methods from the corresponding controllers. You can find the commit for this here.

3. Running the app

At this point our MEAN.JS app ist just about ready to go. One thing left to do would be to prevent server crashes caused by uncaught errors in the main event loop.
This can be solved easily by:

process.on('uncaughtException', function (err) {
    console.log("Uncaught exception at " + new Date());
    console.error(err);
});

This prevents the server process from exiting and it should be used only as a temporary solution. In general, error cases should be dealt with properly.

Another step we should take before running the app is to load the database with some test data. We do this by starting Node.js (ie. launching node.exe) with ./migration/loader.js as an argument. This will fill the "notes" collection of the "notes" database with the data found in ./migration/testdata.json.

We run the app by launching the server. This is done by starting Node.js with server.js as an argument, or Right click on 'server.js' → Run (from WebStorm). You can then start a browser instance and go to http://localhost:1337/


4. Conclusions

We now know the steps required to build a simple and working web application in MEAN.JS. There is much more to talk about and things can go way deeper than that but at the very simplest this would be it.

5. Follow-up

My intention is to expand on this subject. Among the topics I would like to cover in the upcoming posts would be the following:
- testing
- build management
- authentication + passport
- cloud9 + mongolab
- websockets
- migrating to react
- migrating to spring