MongoDB, Express, AngularJS (1.6) and Node.js (MEAN) Part 2

Published Aug 16, 2017Last updated Aug 26, 2017

This is a continuation of the MEAN Series. If you feel the need to start from the basics, go ahead and explore Part 1 of the series.

In this part, we will set up the server file and define routes to serve our application on the browser. We will also look at some AngularJS concepts and how they work together with Node.js on the back-end to make our lives easier.

We’ll be writing our JavaScript code using ECMAScript 6 (ES6), so expect lots of const, let, map and arrow functions. Feel free to check out a resource on ES6 if these terms sound strange or if you feel your JavaScript is getting rusty. Hopefully you'll get some motivation from learning about all the cool stuff we can do using ES6. 😃

Express Server Setup and MongoDB Connection

Let’s create our app entry point. To do this, we create a server.js file in the project root directory with the following code snippet:

// server.js


const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');

const app = express();
const router = express.Router();

// Connect to mongoDB database
const mongoURL = 'mongodb://<dbuser>:<dbpassword>@<host>:<port>/<database-name>';

mongoose.connect(mongoURL);

// Routing

// Configure port
const port = 8080;

// Listen to port
app.listen(port);
console.log(`Server is running on port: ${port}`);

Replace <dbuser>, _<dbpassword>, <host>, <port>_and <database-name> with your MongoDB credentials.

Note:

  • If you’re using MongoDB locally, your host will most likely be localhost. Unless you have a username and password set, your connection string may simply look like this:
mongodb://localhost/<dbname>
  • This will automatically create the database with the name specified in the connection string when you perform an insert query.
  • If you’re using the online version of MongoDB provided by mlab, you’ll need to log into your account, create a database and a database user, and get the connection string, which usually looks like:
mongodb://<dbuser>:<dbpassword>@dsXXXXX.mlab.com:XXXX/<db-name>

We'll go through how to store the connection string, along with other sensitive data, in an environment variable in the next tutorial. This will prevent you from compromising the security of our application and database. In this tutorial, we will allow this data to exist in the server.js for simplicity's sake, but don’t try this in production.😃

The next thing is to start the application on the terminal using:

node server.js

This will log the following on the terminal if successful:

Server is running on port: 8080

If you see this message, then the server connection to MongoDB was successful and our app started successfully. We will now proceed to add some routes and serve some static pages.

Server/Backend Routes

In this step, we'll create the back-end route for the application to enable it to communicate with our server. To achieve this, we're going to modify the server.js file we created earlier and add the following snippet just below Routing:

// server.js

. . .

// Routing

router.get('/', (request, response) => { 
 response.status(200).send({message: 'Hello World!'});
});

// Set app to use express back-end router
app.use(router);
. . .

Now we restart our application, open up a browser, and navigate to http://localhost:8080/

On your browser window, you should see the message:

{"message":"Hello World!"}

If you see this displayed, our back-end route works. Awesome!!!

Now, we'll create HTML files to be rendered on the browser. To do this, we'll run the following UNIX command from the project root directory:

mkdir public && touch public/index.js && touch public/index.html

This will create a public directory and create index.js and index.html files in it.

Our directory structure should look like:

> node_modules> public -- index.html -- index.js-- package.json-- server.js

In the index.js file we'll add the following snippet:

// index.js

angular.module('angularApp', []) .controller('indexCtrl', function($scope) {

// Initialize variables

$scope.name1 = '';

this.name2 = '';

$scope.greeting1 = `Hello ${$scope.name1}`;

this.greeting2 = `Hi ${this.name2}`;
})

Notice that we're defining two variables that seem to be doing the exact same thing but look slightly different. You'll find several different schools of thought on the best way to define variables and methods in an AngularJS controller: $scope has been around for some time, while this just joined the party after Angular 1.2.

I use both depending on how I’m feeling. AngularJS component doc also uses both. Whichever one you choose to use, I think they both achieve the same results. However, whenever you use this , you'll have to instantiate the controller as a variable in the view, like: ng-controller=”indexCtrl as app” as used below, while if you’re using $scope, you only need ng-controller=”indexCtrl”.

If you feel fascinated by the $scope vs this debate, feel free to research further into it and let me know your findings in the comments section.

For now, we’ll focus on their usage. I will use this for most of this tutorial because I feel like it. 😃 Just kidding. I'm using this because I think it reduces the chances of confusing pure text for Angular variables in HTML.

In our index.html file, we'll add the following snippet:

<!doctype html>

<html ng-app="angularApp"> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"> </script>
 <script src="index.js"></script> </head>
 <body>
 <div ng-controller="indexCtrl as app"> 
  <input type="text" ng-model="name1" placeholder="Using $scope variable name" /> 
    <br /> 
    <input type="text" ng-model="app.name2" placeholder="Using this variable name" /> 
    <br /><br /> 
    <h2 ng-if="name1 != ''"> Hello {{name1}} </h2> 
    <br /> 
    <h2 ng-if="app.name2 != ''"> Hi {{app.name2}} </h2> 
  </div>
 </body>
</html>

Now, we'll update our back-end route to render static pages in the public directory. To do this, we'll add the following snippet to our server.js file just above Routing defined earlier:

// Serve static files
app.use(express.static('public'));

We'll also update our initial back-end route to point to/api .

Now our files will look like this:

server.js:

const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const app = express();
const router = express.Router();

// Connect to mongoDB database assuming our database name is "angular-app"
const mongoURL = 'mongodb://localhost/angular-app';
mongoose.connect(mongoURL);

//  Serve frontend view
app.use(express.static('public'));

// Specify backend route
router.get('/api', (request, response) => {
    response.status(200).send({message: 'Hello World!'});
});
app.use(router);

// Configure port
const port = 8080;

// Listen to port
app.listen(port);
console.log(`Server is running on port: ${port}`);

index.js:

angular.module('angularApp', [])
  .controller('indexCtrl', function($scope) {
    // Initialize variables
    $scope.name1 = '';
    this.name2 = '';

    $scope.greeting1 = `Hello ${$scope.name1}`;
    this.greeting2 = `Hi ${this.name2}`;
  });

index.html:

<!doctype html>
<html ng-app="angularApp">
 <head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
  <script src="index.js"></script>
 </head>
 <body>
     <div ng-controller="indexCtrl as app">
         <center>
            <h2>Welcome!</h2>
                <br />
            <h3>Enter your name below:</h3>
            <input type="text" ng-model="name1" placeholder="Scope variable name" />
                <br /><br />
            <input type="text" ng-model="app.name2" placeholder="Controller variable name" />
                <br /><br />
            <h2 ng-if="name1 != ''"> Hello {{name1}} </h2>
                <br />
            <h2 ng-if="app.name2 != ''"> Hi {{app.name2}} </h2>
         </center>
     </div>
 </body>
</html>

Once we have the files above, we'll go ahead and restart our application, then navigate to http://localhost:8080/ on the browser.

We’ll find empty input fields where we can enter text and have hello/hi messages displayed on the browser.

We can also navigate to the http://localhost:8080/ API and access our app API route.


AngularJS Concepts:

The script above featured a few Angular concepts. Let’s talk a bit about them.

We won't dive too deeply into these concepts to avoid getting lost in theoretical stuff. If you’re interested in learning more, I recommend you take a moment to research more about them. I’ll just point out a few relevant concepts.

Modules:

An Angular module is a container for the various parts of our application. It's defined with the angular.module keyword (i.e angularApp in our case).

A module divides an Angular app into smaller reusable components. All controllers and functions in the app must belong to a module. A module can be dependent on other modules — this is achieved using a concept referred to as Dependency Injection (DI).

Every web page view in the app can be instantiated with a module using the ng-app directive, as used in our index.html above.

Directives:

These are DOM manipulators. They tell the Angular compiler which attributes to attach to the DOM element. They start with an ng- prefix.

In the example above, we saw directives such as ng-app, ng-controller, ng-model, and ng-if. There are others, such as: ng-view, ng-show, ng-options, ng-repeat, ng-src, ng-click, ng-change, ng-form, ng-init, ng-switch, ng-href, etc.

These directives are simply awesome. With them, we can make the DOM do whatever we want it to. We can even create our own directives. How cool is that?😃

Directives can also be specified in camelCase. Check out Angular docs for a list of directives and all the cool stuff we can do with them.

2-way data binding:

This leaves us with one of the coolest features of AngularJS — the ability to synchronize data between the model and the view, which implies that any change on one side immediately affects the other. We notice that in our app, when we enter a value in the input field, it immediately reflects on the browser. That is 2-way binding and it's achieved using the ng-model directive.


Summary

We've seen how to connect an Express server to MongoDB, create back-end routes, and also serve static files. We've also seen some of the cool stuff we can do with AngularJS and how easy it is to manipulate DOM operations using Angular directives. All of these are just the tip of the iceberg — we can do a whole lot more with MEAN. We’re just getting started.

In our next tutorial, we'll focus on making database calls and performing create, read, update, and delete (CRUD) operations using RESTful API. We'll also look at how to automate our tasks and set up webpack to bundle our dependencies.

We will also learn how to use nodemon to listen for changes and hot-reload the server. Notice that we used a CDN to import AngularJS into our project — that will change with webpack. We'll also store our application sensitive data in .env to prevent security compromises.

Feel free to leave your comments, suggestions, and/or questions below and I’ll be happy to get back to you.

Resources:

This post is originally published by the author here. This version has been edited for clarity and may appear different from the original post.

Discover and read more posts from Ethan Nwankwo
get started
Enjoy this post?

Leave a like and comment for Ethan

18
7
7Replies
vibhor kashyap
a month ago

// server.js
const express = require(‘express’);
const bodyParser = require(‘body-parser’);
const mongoose = require(‘mongoose’);

const app = express();
const router = express.Router();

// Connect to mongoDB database
const mongoURL = ‘mongodb://127.0.0.1/test’;

mongoose.connect(mongoURL);

// Routing
router.get(’/’, (request, response) => {
response.status(200).send({message: ‘Hello World!’});
});

// Configure port
const port = 8080;

// Listen to port
app.listen(port);
console.log(Server is running on port: ${port});

I GET THIS IN BROWSER :

Cannot GET /

Ethan Nwankwo
a month ago

Hi Vibhor,
I notice that you have not set the app to use express router.
To do this, Add app.use(router); after specifying the routes, just before assigning the port.

Fortune Ekeruo
a month ago

Great article! Super awesome mentor! Keep it up

Ethan Nwankwo
a month ago

Thanks Fortune

Muhammad Asif
a month ago

Great article, is there any way to get notified about the next part of this series, without getting spam?

Ethan Nwankwo
a month ago

Hi Muhammad, thanks for your compliment. I think once you follow my account, you will get notified when there is a new post.

Muhammad Asif
a month ago

That’d be great :) Waiting for the next part

Show more replies

Get curated posts in your inbox

Read more posts to become a better developer