How to make a Front-End Application using the MEAN Stack

Ali Bhatti
14 min readSep 19, 2016

Let’s get lean and mean with the MEAN STACK!

In this tutorial, I’ll walk you through step-by-step to create an awesome grocery list sharing application that includes authentication, saving user-generated content to your MongoDB using Mongoose, all the client-side (front-end) and server-side (back-end) routing, and some cool CSS tricks using UI-Bootstrap (Bootstrap for Angular applications).

What’s MEAN?

TL;DR -> MEAN Tech Stack: MongoDB, ExpressJS, AngularJS, NodeJS

When I was first introduced to tech stacks and heard about the MEAN stack I knew I had to learn it…it just sounded cool! But as I learned different front-end and back-end frameworks I quickly learned that there are many different technology options available in a full-stack web application, and MEAN just happens to have gained popularity recently.

Note: MEAN can mean different tech stacks to different developers so it’s often good to clarify what someone means when they say MEAN. Also it’s possible to have the above MEAN stack combined with other technologies such as React.

MongoDB: A NoSql database that stores data in object-like documents. Since the data is being stored in objects, that means that objects can have all kinds of different data types, or even have hierarchy with nested objects, etc. Some documents in a collection can vary and have some or even none of the same property types as other documents stored in the same collection. This is completely different than SQL databases such as MySql where the data fields are defined in advanced by the schema, and they are all of fixed length and type. Mongoose (an ORM for MongoDB) adds a layer of abstraction allowing you to make a very English-like queries to the MongoDB. (We’ll get into details as we implement the MongoDB.) Official Site here. More info on Mongoose here.

ExpressJS: A server built on top of NodeJS allowing you to write sever-side code purely in Javascript without the need to learn any other scripting language. Basic setup for Express literally takes just a few minutes. Node already allows you to get a server up, but Express simplifies the process with easier code. Express also lets you use middleware which simplifies managing different routes amongst other things. In a nutshell: It does a lot of the heavy-lifting for you in terms of difficult Node code and lets you get your server up fast using its easy framework. Official Site here.
Useful introduction to Express here.

AngularJS: A widely popular front-end MVC Javascript framework built by the geniuses at Google. There are many advantages of using Angular, but one of my favorites is 2-way data binding whereby anytime data is changes anywhere then the references to that data will automatically update everywhere in the application. Official site here.

NodeJS: Server-side (back-end) JS framework (although technically not defined as a framework). NodeJS lets you create a basic web server and networking tools along with a bunch of modules that come out out of the box that let you handle core functionality. The folks that built NodeJS define it as ‘a JavaScript runtime built on Chrome’s V8 JavaScript engine. NodeJS uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. NodeJS’ package ecosystem, NPM, is the largest ecosystem of open source libraries in the world’. Go here for more info.

MVC Framework: An easy way to breakup your Javascript code into a Model section that manipulates data, a View section that renders content to the browser, and a Controller section that contains the logic behind how to process changes to the data and manipulate the view as a result.

Steps to Build a MEAN Web Application

Enough of the boring stuff, let’s dive in shall we?

What we’ll build:

Check out the live deployed web app here

Also in this tutorial I’m only including code snippets, but I know you’ll likely want to play with the code so please check it out on github here.

Basic Steps that we’ll cover:

  1. Setup Node/Express Server
  2. Setup MongoDB/Mongoose for database
  3. Build out front-end with AngularJS and UI-Boostrap (CSS)

Some Assumptions and Prerequisites before starting:

  1. You should know how to use a text editor like SublimeText3 or Atom.
  2. Be comfortable with Terminal/CLI(cmd line)
  3. Have Node installed globally on system (goto Node site, follow instructions)
  4. Have a basic understanding of JavaScript, HTML, CSS fundamentals.

Step 1: Setting up Node/Express Server

In this section we’ll cover: installing NPM dependencies you’ll need, setting up your file directories, setting up your Middleware and Routing, and getting your Express Server up and running.

Part A: Install NPM Dependencies

  1. Create a file in your root folder named: package.json
  2. In package.json ensure you have all of the dependencies listed below. Feel free to change name, version, description, etc. to whatever you like as they’re all optional. Include the scripts and the dependencies exactly as written in the code below. Note that some of the dependencies are not crucial and I won’t be elaborating on how to use them in this tutorial such as all of the testing modules (Sinon, Supertest,Mocha, Chai)

3. In Terminal goto Root folder and then type: npm install (that will download all of your modules to a new folder it will automatically create in your root called node_modules. (Note: If you ever want to download or try a new npm module, simply type npm install - -save “type module name here”

Part B: Setup File Directories

  1. In root folder, create following folders: client, server
  2. In root folder, create following file: index.js

Part C: Start Express Server

  1. Under server folder > Create folder: config > Create files in config: helpers.js, middleware.js, routes.js

2. Under server folder > create server.js file

3. In server.js file you will start express server, setup routes and export the server.

  • You’ll need to require express, middleware, routes

Part D: Setup Middleware

In config/middleware.js file:

  • Require morgan, bodyParser
  • Morgan is used for middleware
  • bodyParser is used for parsing
  • express.static will be used to serve up the initial homepage from the client folder.

Part E: Setup Routing

In routes.js, you can define all of your server-side routing and have them all exported.

Anatomy of a Route:
- Specify CRUD (get, post, put, delete)
- Define the URL where the api call will be coming from (eg. front-end app might do a get request to the url: /api/signup)
- Define a function that will do something and return a response.
(Best practice: require a file that will have all of the functions as methods so you can simply state the method name, see below code for clarity)

Note: In example below, I’m requiring userHandler and listHandler. You’ll need to create the /users and /lists folder under server folder, and you’ll need to also create the userHandler and listHandler.js files. I’ll get into the details after we get the server up.

For testing, in addition to all of the routes in the code below, add the following:
app.get(‘/test’, function(req,res){
res.json(‘hey hey hey I’m aliiiive!’)
});

Part F: Setup index.html
In client folder > create index.html

Just create a basic html page with any text in the body for testing.

Part G: Setup MongoDB with Mongoose

Set your mongoURI to ‘mongod://localhost/ANY-NAME-YOU-LIKE
Connect db: mongoose.connect(mongoURI);
Set Port to any available port numbers (1337, 8080, 3000, etc.)
Listen on port and console log a message to ensure you can see in the terminal when your server is up.

Example Code:

Part H: Test the Express Server!

1) Save all your code!

2) goto Terminal open 2 tabs (Cmd T) and goto your root directory for your application

3) type mongod (note: Since this is the first time, you may actually need to go to the MongoDB Site, follow instructions on how to get Mongo properly installed globally to your system so you can run the mongod command without any issues/errors.)

The trickiest part with MongoDB is the initial installation.

After running mongod, you should see something like this:

4) In 2nd terminal tab, type npm start

(Remember: package.json we had defined the script for “start” to basically just be “node index.js” and that will start up our express server.

If all works well, you should see something like below:

Now just open up your Chrome browser and type: localhost: 1337
That should bring up your static html page!
Also goto url and type in localhost:1337/test, and you should see our test message displayed: “hey hey hey”

CELEBRATE!

You just got your server up and running with a bunch of server-side routing in place! Let’s keep going shall we?

STEP 2: Setting Up MongoDB

Creating Schemas

We’re going to use Mongoose (an ORM) which will setup our schemas and manipulate our data with our MongoDB.

For this step, we need to come up with a schema which will server as our default document (Mongo object) with properties value types.

For our example project, the Grocery Cart List app, we will want to store 2 seperate types of data: List and User.

The List schema will have info such as the name of the list, due date of the list, list items, etc. The User schema will have all the user info such as username, email, password, etc.

Create a listModel.js and userModel.js files in their respective list and users folders. Each file should include mongoose.

The user file should also include bcrypt which we’ll be using for authentication. I have included a couple of bcrypt methods (comes with the bcrypt library) to help with this: comparePassword and a preSave. The comparePassword method simply compares the entered login password to the hashed password we have stored in the User collection, and the preSave method simply hashes the password with a salt before saving. Authentication is a bit out of scope for this tutorial, but you can learn more about bcrypt and authentication here.

After creating the schemas each model should be exported.

General form of creating a schema

var nameOfSchema = new mongoose.Schema({propertyName: keyValueType, …})

See example code below.

userModel.js

listModel.js

Setting Up Handlers for Routes

If you recall, back when we setup the routes we had each route triggering a function invocation (look at the 2nd argument in the get below, the function reference to be invoked is listHandler.getLists)

Example:

listHandler.getLists method will be invoked with this get request

In the routes.js file we include userHandler.js and listHandler.js with require statements as follows thus making it possible for us to have access to all of their methods (such as listHandler.getLists)…if this is confusing, it will make a lot more sense when you see the listHandler.js file as it will show you that we are exporting all of the methods as part of a listHandler object.

routes.js requires userHandler and listHandler.js

listHandler.js

Our list handler will have several important methods that are invoked based on specific CRUD requests. Since we will be accessing our MongoDB, we will need to require our User and List models. I’ve also included an additional helpers.js file just to simply send back an error message when needed.

The code is quite self-explanatory, but I’ll give a quick summary of each method we’ll need. Note that it’s more important generally from a high level that you understand what the methods are doing, and how we’re accessing the MongoDB to update, delete, get data, etc. You do not actually need to have all of the methods below, just choose what’s important based on what you’re building out.

  1. addList: Used to pass on a new list to our List DB.
  2. updateList: This is used when we need to update a list. In our example we update our list when a user of our crowdsourcing grocery list app wants to select someone else’s grocery list to take on as a “job” and be a deliverer, thus we update the list to assign a deliverer_id. Note the usage of List.findOne which is the Mongoose way of querying the MongoDB.
  3. deleteList: Removes a list.
  4. getOneList: Finds a specific list based on an id.
  5. getLists: Gets all lists where the passed in id matches.
  6. getAllLists: Returns all lists in db.
  7. getJobs: Returns all lists that match the passed in delieverer id.
  8. updateStatus: Assigns deliverer_id to list id when appropriate.

userHandler.js

This file should take care of the signin and signup. The code is very self-explanatory, but essentially the signin method takes in email/password that was entered by user and then looks in User model for matching email, if found then does a check for matching password and if so then assigns a session token along with the userid and sends back to user.

Signup method is very simple: takes in email and new user object (created from sign up page) and then checks email in DB and if not found then creates a new document in User model with user info. If there is a user found then send an error back.

Example code below:

helpers.js file should be in config folder

STEP 3: Setup Front-end with AngularJS

Setup HTML Page

  1. Create index.html if you haven’t already done so and save it in the client folder.
  2. In order to “angularize” the front-end you can add ng-app=”whatever-app-name” to the initial <html> tag.
  3. Within the body, add a div with ng-view attribute, this will be used to display any of the views that we’ll be displaying. Note: We’re using Angular Router for routing on the front-end, but if we wanted to have multiple different views rendering at the same time it’s best to use ui-router.
  4. Any elements can be controlled by a controller (we’ll get into controllers in a little bit) so for example you can have <body ng-controller=”AppController”>

Here’s the example code, just note that there’s some ui-bootstrap attributes such as uib-accordian-group that you can learn about here.

Setup App.js and Client-Side Routing

  1. Add app.js file under the client folder.
  2. This is where we essentially create the main rendering module which will have dependencies on other view modules.

We create the initial module (we’ll call it “crowdcart”).
In below example, “crowdcart” is the name of the app, the 2nd argument array is a list of all the dependencies which are related views:

3. Then we setup the client-side routing using a .config

In the below example, .when takes in a specific route, 2nd argument is an object that contains a templateUrl that should be displayed along with its accompanying controller. In the example below, line 16 shows AuthController, this controller is found in the “crowdcart.auth” module (see above code snippet line 3). We’ll get into the details regarding both the html file and controller module files.

.otherwise is a redirect when no route given

4. Each module will have a definition of its controller and factory, however, since our main app is being defined in app.js, any controllers/factories need to be defined in this file as well.

Below we have the main app controller, factory, and a run directive that manage authentication:

Setup Authentication

  1. Create auth folder under client folder
  2. Add files to auth folder: auth.js, signin.html, signup.html

I won’t go into too much detail as the code is quite self-explanatory, but essentially the signin and signup html pages are views that will get rendered based upon client-side routing that we defined in the previous step.

signin.html

signup.html

auth.js

I want to spend a little time here in auth.js explaining what’s happening.

  1. It’s similar to app.js in that we define our module name as the 1st argument to angular.module.
  2. Add any dependencies as 2nd argument. (Here we are including something called $scope which is KEY to Angular 2-way data binding. The same $scope object will be used in the html files and if anything is changed in the object’s properties, they’ll be changed anywhere else it’s being referenced. $window and $location are also special Angular key terms that you can lookup to find out more info, but essentially $window gives you access to storing in the window on the client-side (local storage, see below in code example), while $location gives you access to the path (see below in line 26 to see how its being used).

Setup Jobs files

I want to just use the jobs module and views to show you an example of how $scope used, and more importantly how the controller controls the view.

  1. Our jobs folder should have the following files added: jobs.js, findjobs.html, myjobs.html
  2. jobs.js contains the module and controller for these html views.

Examine how the $scope is being used between jobs.js where we define the controller, and the html files. This is a key takeaway to observe.

jobs.js

myjobs.html

Key takeaways below:

  1. Line 15: ng-repeat is similar to _Each where it will iterate through data.jobs. Look at the above code snippet at line 13: $scope.data.jobs. Line 13 is populated with all the jobs after the Jobs.getJobs function is called which is referring to a factory called Jobs method that is an API call to get the jobs data from the server side (defined in services.js — see services.js snippet to understand how the Jobs factory works).

Jobs Factory located in services.js

  1. add services.js to a services folder under the client folder

Lists Folder

Now that we’ve defined the Jobs module and html views, you have a much better understanding of how $scope can be used for 2-way data binding.

I’ve purposely left out the last folder, Lists, as it’s a very large folder and essentially has very similar code to the Jobs folder example I have above. You can access all of the code including the Lists folder from my github page.

CONCLUSION

Checkout my github project for all the files including the missing Lists folder that I didn’t include here.

Here’s a link to my app on Heroku so you can take for a spin before building it!

If you read this far, you’ve survived! Making a bare-bones app is even easier than all of the code I’ve included, but I wanted to give you a general idea of a small working app that has different views, a DB, authentication, etc.

Have fun with the MEAN stack making great apps and leave me a not so mean post with your questions/comments! :-) :-) :-)

--

--

Ali Bhatti

Fullstack Developer, Product Manager, Husband & Father