Chapter 5: MEAN Stack: Build an App with Angular 2+ and the Angular CLI

by Manjunath M

The MEAN stack comprises advanced technologies used to develop both the server-side and the client-side of a web application in a JavaScript environment. The components of the MEAN stack include the MongoDB database, Express.js (a web framework), Angular (a front-end framework), and the Node.js runtime environment. Taking control of the MEAN stack and familiarizing different JavaScript technologies during the process will help you in becoming a full-stack JavaScript developer.

JavaScript’s sphere of influence has dramatically grown over the years and with that growth, there’s an ongoing desire to keep up with the latest trends in programming. New technologies have emerged and existing technologies have been rewritten from the ground up (I’m looking at you, Angular).

This tutorial intends to create the MEAN application from scratch and serve as an update to the original MEAN stack tutorial. If you’re familiar with MEAN and want to get started with the coding, you can skip to the overview section.

Introduction to the MEAN Stack

Node.js - Node.js is a server-side runtime environment built on top of Chrome's V8 JavaScript engine. Node.js is based on an event-driven architecture that runs on a single thread and a non-blocking IO. These design choices allow you to build real-time web applications in JavaScript that scale well.

Express.js - Express is a minimalistic yet robust web application framework for Node.js. Express.js uses middleware functions to handle HTTP requests and then either return a response or pass on the parameters to another middleware. Application-level, router-level, and error-handling middlewares are available in Express.js.

MongoDB - MongoDB is a document-oriented database program where the documents are stored in a flexible JSON-like format. Being an NoSQL database program, MongoDB relieves you from the tabular jargon of the relational database.

Angular - Angular is an application framework developed by Google for building interactive Single Page Applications. Angular, originally AngularJS, was rewritten from scratch to shift to a Component-based architecture from the age old MVC framework. Angular recommends the use of TypeScript which, in my opinion, is a good idea because it enhances the development workflow.

Now that we’re acquainted with the pieces of the MEAN puzzle, let’s see how we can fit them together, shall we?

Overview

Here’s a high-level overview of our application.

High-level overview of our MEAN stack application

We’ll be building an Awesome Bucket List Application from the ground up without using any boilerplate template. The front end will include a form that accepts your bucket list items and a view that updates and renders the whole bucket list in real time.

Any update to the view will be interpreted as an event and this will initiate an HTTP request. The server will process the request, update/fetch the MongoDB if necessary, and then return a JSON object. The front end will use this to update our view. By the end of this tutorial, you should have a bucket list application that looks like this.

Screenshot of the bucket list application that we are going to build

The entire code for the Bucket List application is available on GitHub.

Prerequisites

First things first, you need to have Node.js and MongoDB installed to get started. If you’re entirely new to Node, I would recommend reading the Beginner’s Guide to Node to get things rolling. Likewise, setting up MongoDB is easy and you can check out their documentation for installation instructions specific to your platform.

$ node -v
# v8.0.0

Start the mongo daemon service using the command.

sudo service mongod start

To install the latest version of Angular, I would recommend using Angular CLI. It offers everything you need to build and deploy your Angular application. If you’re not familiar with the Angular CLI yet, make sure you check out The Ultimate Angular CLI Reference.

npm install -g @angular/cli

Create a new directory for our bucket list project. That’s where both the front-end and the back-end code will go.

mkdir awesome-bucketlist
cd awesome-bucketlist

Creating the Backend Using Express.js and MongoDB

Express doesn’t impose any structural constraints on your web application. You can place the entire application code in a single file and get it to work, theoretically. However, your codebase would be a complete mess. Instead, we’re going to do this the MVC way (Model, View, and Controller)—minus the view part.

MVC is an architectural pattern that separates your models (the back end) and views (the UI) from the controller (everything in between), hence MVC. Since Angular will take care of the front end for us, we’ll have three directories, one for models and another one for controllers, and a public directory where we’ll place the compiled angular code.

In addition to this, we’ll create an app.js file that will serve as the entry point for running the Express server.

Directory structure of MEAN stack

Although using a model and controller architecture to build something trivial like our bucket list application might seem essentially unnecessary, this will be helpful in building apps that are easier to maintain and refactor.

Initializing npm

We’re missing a package.json file for our back end. Type in npm init and, after you’ve answered the questions, you should have a package.json made for you.

We’ll declare our dependencies inside the package.json file. For this project we’ll need the following modules:

  • express: Express module for the web server
  • mongoose: A popular library for MongoDB
  • bodyparser: Parses the body of the incoming requests and makes it available under req.body
  • cors: CORS middleware enables cross-origin access control to our web server.

I’ve also added a start script so that we can start our server using npm start.

{
  "name": "awesome-bucketlist",
  "version": "1.0.0",
  "description": "A simple bucketlist app using MEAN stack",
  "main": "app.js",
  "scripts": {
    "start": "node app"
  },

//The ~ is used to match the most recent minor version (without breaking changes)

 "dependencies": {
    "express": "~4.15.3",
    "mongoose": "~4.11.0",
    "cors": "~2.8.3",
    "body-parser": "~1.17.2"
  },

  "author": "",
  "license": "ISC"
}

Now run npm install and that should take care of installing the dependencies.

Filling in app.js

First, we require all of the dependencies that we installed in the previous step.

// We’ll declare all our dependencies here
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');

//Initialize our app variable
const app = express();

//Declaring Port
const port = 3000;

As you can see, we’ve also initialized the app variable and declared the port number. The app object gets instantiated on the creation of the Express web server. We can now load middleware into our Express server by specifying them with app.use().

//Middleware for CORS
app.use(cors());

//Middleware for bodyparsing using both json and urlencoding
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());

/*express.static is a built in middleware function to serve static files.
 We are telling express public folder is the place to look for the static files
*/
app.use(express.static(path.join(__dirname, 'public')));

The app object can understand routes too.

app.get('/', (req,res) => {
    res.send("Invalid page");
})

Here, the get method invoked on the app corresponds to the GET HTTP method. It takes two parameters, the first being the path or route for which the middleware function should be applied.

The second is the actual middleware itself, and it typically takes three arguments: the req argument corresponds to the HTTP Request; the res argument corresponds to the HTTP Response; and next is an optional callback argument that should be invoked if there are other subsequent middlewares that follow this one. We haven’t used next here since the res.send() ends the request–response cycle.

Add this line towards the end to make our app listen to the port that we had declared earlier.

//Listen to port 3000
app.listen(port, () => {
    console.log(`Starting the server at port ${port}`);
});

npm start should get our basic server up and running.

By default, npm doesn’t monitor your files/directories for any changes, and you have to manually restart the server every time you’ve updated your code. I recommend using nodemon to monitor your files and automatically restart the server when any changes are detected. If you don't explicitly state which script to run, nodemon will run the file associated with the main property in your package.json.

npm install -g nodemon
nodemon

We’re nearly done with our app.js file. What’s left to do? We need to

  1. connect our server to the database
  2. create a controller, which we can then import to our app.js.

Setting up mongoose

Setting up and connecting a database is straightforward with MongoDB. First, create a config directory and a file named database.js to store our configuration data. Export the database URI using module.exports.

// 27017 is the default port number.
module.exports = {
    database: 'mongodb://localhost:27017/bucketlist'
}

And establish a connection with the database in app.js using mongoose.connect().

// Connect mongoose to our database
const config = require('./config/database');
mongoose.connect(config.database);

“But what about creating the bucket list database?”, you may ask. The database will be created automatically when you insert a document into a new collection on that database.

Working on the controller and the model

Now let’s move on to create our bucket list controller. Create a bucketlist.jsfile inside the controller directory. We also need to route all the /bucketlist requests to our bucketlist controller (in app.js).

const bucketlist = require('./controllers/bucketlist');

//Routing all HTTP requests to /bucketlist to bucketlist controller
app.use('/bucketlist',bucketlist);

Here’s the final version of our app.js file.

// We’ll declare all our dependencies here
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const config = require('./config/database');
const bucketlist = require('./controllers/bucketlist');

//Connect mongoose to our database
mongoose.connect(config.database);

//Declaring Port
const port = 3000;

//Initialize our app variable
const app = express();

//Middleware for CORS
app.use(cors());

//Middlewares for bodyparsing using both json and urlencoding
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());



/*express.static is a built in middleware function to serve static files.
 We are telling express server public folder is the place to look for the static files

*/
app.use(express.static(path.join(__dirname, 'public')));


app.get('/', (req,res) => {
    res.send("Invalid page");
})


//Routing all HTTP requests to /bucketlist to bucketlist controller
app.use('/bucketlist',bucketlist);


//Listen to port 3000
app.listen(port, () => {
    console.log(`Starting the server at port ${port}`);
});

As previously highlighted in the overview, our awesome bucket list app will have routes to handle HTTP requests with GET, POST, and DELETE methods. Here’s a bare-bones controller with routes defined for the GET, POST, and DELETE methods.

//Require the express package and use express.Router()
const express = require('express');
const router = express.Router();

//GET HTTP method to /bucketlist
router.get('/',(req,res) => {
    res.send("GET");
});

//POST HTTP method to /bucketlist

router.post('/', (req,res,next) => {
    res.send("POST");

});

//DELETE HTTP method to /bucketlist. 
//Here, we pass in a params which is the object id.
router.delete('/:id', (req,res,next)=> {
    res.send("DELETE");

})

module.exports = router;

I’d recommend using Postman app or something similar to test your server API. Postman has a powerful GUI platform to make your API development faster and easier. Try a GET request on http://localhost:3000/bucketlist and see whether you get the intended response.

And as obvious as it seems, our application lacks a model. At the moment, our app doesn’t have a mechanism to send data to and retrieve data from our database.

Create a list.js model for our application and define the bucket list Schema as follows:

//Require mongoose package
const mongoose = require('mongoose');

//Define BucketlistSchema with title, description and category
const BucketlistSchema = mongoose.Schema({
    title: {
        type: String,
        required: true
    },
    description: String,
    category: {
        type: String,
        required: true,
        enum: ['High', 'Medium', 'Low']
    }
});

When working with mongoose, you have to first define a Schema. We have defined a BucketlistSchema with three different keys (title, category, and description). Each key and its associated SchemaType defines a property in our MongoDB document. If you’re wondering about the lack of an id field, it's because we’ll be using the default _id that will be created by Mongoose.

Mongoose Assigns _id Fields by Default

Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema constructor. The type assigned is an ObjectId to coincide with MongoDB's default behavior.

You can read more about it in the Mongoose Documentation

However, to use our Schema definition we need to convert our BucketlistSchema to a model and export it using module.exports. The first argument of mongoose.model is the name of the collection that will be used to store the data in MongoDB.

const BucketList = module.exports = mongoose.model('BucketList', BucketlistSchema );

Apart from the schema, we can also host database queries inside our BucketList model and export them as methods.

//BucketList.find() returns all the lists
module.exports.getAllLists = (callback) => {
    BucketList.find(callback);
}

Here we invoke the BucketList.find method which queries the database and returns the BucketList collection. Since a callback function is used, the result will be passed over to the callback.

Let’s fill in the middleware corresponding to the GET method to see how this fits together.

const bucketlist = require('../models/List');

//GET HTTP method to /bucketlist
router.get('/',(req,res) => {
    bucketlist.getAllLists((err, lists)=> {
        if(err) {
            res.json({success:false, message: `Failed to load all lists. Error:
                ➥ ${err}`});
        }
        else {
            res.write(JSON.stringify({success: true, lists:lists},null,2));
            res.end();

    }
    });
});

We’ve invoked the getAllLists method and the callback takes two arguments, error and result.

All callbacks in Mongoose use the pattern: callback(error, result). If an error occurs executing the query, the error parameter will contain an error document, and result will be null. If the query is successful, the error parameter will be null, and the result will be populated with the results of the query.

-- MongoDB Documentation

Similarly, let’s add the methods for inserting a new list and deleting an existing list from our model.

//newList.save is used to insert the document into MongoDB
module.exports.addList = (newList, callback) => {
    newList.save(callback);
}

//Here we need to pass an id parameter to BUcketList.remove
module.exports.deleteListById = (id, callback) => {
    let query = {_id: id};
    BucketList.remove(query, callback);
}

We now need to update our controller’s middleware for POST and DELETE also.

//POST HTTP method to /bucketlist

router.post('/', (req,res,next) => {
    let newList = new bucketlist({
        title: req.body.title,
        description: req.body.description,
        category: req.body.category
    });
    bucketlist.addList(newList,(err, list) => {
        if(err) {
            res.json({success: false, message: `Failed to create a new list. Error:
                ➥ ${err}`});

        }
        else
            res.json({success:true, message: "Added successfully."});

    });
});

//DELETE HTTP method to /bucketlist. Here, we pass in a param which is the object id.

router.delete('/:id', (req,res,next)=> {
  //access the parameter which is the id of the item to be deleted
    let id = req.params.id;
  //Call the model method deleteListById
    bucketlist.deleteListById(id,(err,list) => {
        if(err) {
            res.json({success:false, message: `Failed to delete the list. Error:
                ➥ ${err}`});
        }
        else if(list) {
            res.json({success:true, message: "Deleted successfully"});
        }
        else
            res.json({success:false});
    })
});

With this, we have a working server API that lets us create, view, and delete the bucket list. You can confirm that everything is working as intended by using Postman.

POST HTTP request using Postman

We’ll now move on to the front end of the application using Angular.

Building the Front End Using Angular

Let’s generate the front-end Angular application using the Angular CLI tool that we set up earlier. We’ll name it angular-src and place it under the awesome-bucketlist directory.

ng new angular-src

We now have the entire Angular 2 structure inside our awesome-bucketlist directory. Head over to the .angular-cli.json and change the ‘outDir’ to "../public".

The next time you run ng build — which we’ll do towards the end of this tutorial — Angular will compile our entire front end and place it in the public directory. This way, you’ll have the Express server and the front end running on the same port.

But for the moment, ng serve is what we need. You can check out the boilerplate Angular application over at http://localhost:4200.

The directory structure of our Angular application looks a bit more complex than our server’s directory structure. However, 90% of the time we’ll be working inside the src/app/ directory. This will be our work space, and all of our components, models, and services will be placed inside this directory. Let’s have a look at how our front end will be structured by the end of this tutorial.

Angular MEAN app architecture

Creating Components, a Model, and a Service

Let’s take a step-by-step approach to coding our Angular application. We need to:

  1. create two new components called ViewListComponent and AddListComponent
  2. create a model for our List, which can then be imported into our components and services
  3. generate a service that can handle all the HTTP requests to the server
  4. update the AppModule with our components, service, and other modules that may be necessary for this application.

You can generate components using the ng generate component command.

ng generate component AddList
ng generate component ViewList

You should now see two new directories under the src/app folder, one each for our newly created components. Next, we need to generate a service for our List.

ng generate service List

I prefer having my services under a new directory(inside src/app/).

mkdir services
mv list.service.ts services/

Since we’ve changed the location of list.service.ts, we need to update it in our AppModule. In short, AppModule is the place where we’ll declare all our components, services, and other modules.

The generate command has already added our components into the appModule. Go ahead and import ListService and add it to the providers array. We also need to import FormsModule and HTTPModule and declare them as imports. FormsModule is needed to create the form for our application and HTTPModule for sending HTTP requests to the server.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { HttpModule } from '@angular/http';
import { FormsModule} from '@angular/forms';
import { AppComponent } from './app.component';

import { AddListComponent } from './add-list/add-list.component';
import { ViewListComponent } from './view-list/view-list.component';
import { ListService } from './services/list.service';
@NgModule({
  declarations: [
    AppComponent,

    AddListComponent,
    ViewListComponent
  ],

  //Modules go here
  imports: [

    BrowserModule,
    HttpModule,
    FormsModule
  ],
  //All the services go here
  providers: [ListService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Now we are in a position to get started with our components. Components are the building blocks in an Angular 2 application. The AppComponent is the default component created by Angular. Each component consists of:

  • a TypeScript class that holds the component logic
  • an HTML file and a stylesheet that define the component UI
  • an @Component decorator, which is used to define the metadata of the component.

We’ll keep our AppComponent untouched for the most part. Instead, we’ll use the two newly created components, AddList and ViewList, to build our logic. We’ll nest them inside our AppComponent as depicted in the image below.

Overview of the component hierarchy in our application

We now have a hierarchy of components — the AppComponent at the top, followed by ViewListComponent and then AddListComponent.

/*app.component.html*/

<!--The whole content below can be removed with the new code.-->
<div style="text-align:center">
  <h1>
     {{title}}!
  </h1>

  <app-view-list> </app-view-list>

</div>
/*view-list.component.html*/

  <app-add-list> </app-add-list>

Create a file called List.ts under the models directory. This is where we’ll store the model for our List.

/* List.ts */

export interface List {
    _id?: string;
    title: string;
    description: string;
    category: string;

}

View-List Component

The ViewListComponent’ component's logic includes:

  1. lists property that is an array of List type. It maintains a copy of the lists fetched from the server. Using Angular’s binding techniques, component properties are accessible inside the template.
  2. loadLists() loads all the lists from the server. Here, we invoke this.ListSev.getAllLists() method and subscribe to it. getAllLists() is a service method (we haven't defined it yet) that performs the actual http.get request and returns the list; loadLists() then loads it into the Component’s list property.
  3. deleteList(list) handles the deletion procedure when the user clicks on the Delete button. We’ll call the List service’s deleteList method with id as the argument. When the server responds that the deletion is successful, we call the loadLists() method to update our view.
/*view-list.component.ts*/

import { Component, OnInit } from '@angular/core';
import { ListService } from '../services/list.service';
import { List } from '../models/List'

@Component({
  selector: 'app-view-list',
  templateUrl: './view-list.component.html',
  styleUrls: ['./view-list.component.css']
})
export class ViewListComponent implements OnInit {

  //lists propoerty which is an array of List type
  private lists: List[] = [];

  constructor(private listServ: ListService) { }

  ngOnInit() {

    //Load all list on init
    this.loadLists();
  }

  public loadLists() {

    //Get all lists from server and update the lists property
    this.listServ.getAllLists().subscribe(
        response => this.lists = response,)
  }

  //deleteList. The deleted list is being filtered out using the .filter method
  public deleteList(list: List) {
    this.listServ.deleteList(list._id).subscribe(
      response =>    this.lists = this.lists.filter(lists => lists !== list),)
    }

}

The template (view-list.component.html) should have the following code:

  <h2> Awesome Bucketlist App </h2>

  <!-- Table starts here -->
  <table id="table">
      <thead>
        <tr>
          <th>Priority Level</th>
          <th>Title</th>
          <th>Description</th>
          <th> Delete </th>

        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let list of lists">
          <td>{{list.category}}</td>
          <td>{{list.title}}</td>
          <td>{{list.description}}</td>
          <td> <button type="button" (click)="deleteList(list); $event.
          ➥stopPropagation();">Delete</button></td>

        </tr>
      </tbody>
   </table>

<app-add-list> </app-add-list>

We’ve created a table to display our lists. There’s a bit of unusual code in there that is not part of standard HTML. Angular has a rich template syntax that adds a bit of zest to your otherwise plain HTML files. The following is part of the Angular template syntax.

  • The *ngFor directive lets you loop through the lists property.
  • Here list is a template variable whereas lists is the component property.
  • We have then used Angular’s interpolation syntax {{ }} to bind the component property with our template.
  • The event binding syntax is used to bind the click event to the deleteList() method.

We’re close to having a working bucket list application. Currently, our list.service.ts is blank and we need to fill it in to make our application work. As highlighted earlier, services have methods that communicate with the server.

/*list.service.ts*/

import { Injectable } from '@angular/core';
import { Http,Headers } from '@angular/http';
import {Observable} from 'rxjs/Observable';
import { List } from '../models/List'

import 'rxjs/add/operator/map';

@Injectable()
export class ListService {

    constructor(private http: Http) { }

    private serverApi= 'http://localhost:3000';

    public getAllLists():Observable<List[]> {

        let URI = `${this.serverApi}/bucketlist/`;
        return this.http.get(URI)
            .map(res => res.json())
            .map(res => <List[]>res.lists);
    }

    public deleteList(listId : string) {
      let URI = `${this.serverApi}/bucketlist/${listId}`;
        let headers = new Headers;
        headers.append('Content-Type', 'application/json');
        return this.http.delete(URI, {headers})
        .map(res => res.json());
    }
}

The underlying process is fairly simple for both the methods:

  1. we build a URL based on our server address
  2. we create new headers and append them with { Content-Type: application/json }
  3. we perform the actual http.get/http.delete on the URL
  4. We transform the response into json format.

If you’re not familiar with writing services that communicate with the server, I would recommend reading the tutorial on Angular and RxJS: Create an API Service to Talk to a REST Backend.

Head over to http://localhost:4200/ to ensure that the app is working. It should have a table that displays all the lists that we have previously created.

Add-List Component

We’re missing a feature, though. Our application lacks a mechanism to add/create new lists and automatically update the ViewListComponent when the list is created. Let’s fill in this void.

The AddListComponent’s template is the place where we’ll put the code for our HTML form.

<div class="container">

    <form (ngSubmit)="onSubmit()">
      <div>
        <label for="title">Title</label>
        <input type="text" [(ngModel)]="newList.title" name="title" required>
      </div>

      <div>
        <label for="category">Select Category</label>
        <select [(ngModel)]="newList.category" name = "category" >

            <option value="High">High Priority</option>
            <option value="Medium">Medium Priority</option>
            <option value="Low">Low Prioirty</option>

        </select>
      </div>

      <div>
        <label for="description">description</label>
        <input type="text" [(ngModel)]="newList.description" name="description"
        ➥ required>
      </div>

      <button type="submit">Submit</button>

    </form>
</div>

Inside our template, you can see several instances of [(ngModel)] being used. The weird-looking syntax is a directive that implements two-way binding in Angular. Two-way binding is particularly useful when you need to update the component properties from your view and vice versa.

We use an event-binding mechanism (ngSubmit) to call the onSubmit() method when the user submits the form. The method is defined inside our component.

/*add-list.component.ts*/

import { Component, OnInit } from '@angular/core';
import { List } from '../models/List';
import { ListService } from '../services/list.service';

@Component({
  selector: 'app-add-list',
  templateUrl: './add-list.component.html',
  styleUrls: ['./add-list.component.css']
})
export class AddListComponent implements OnInit {
  private newList :List;

  constructor(private listServ: ListService) { }

  ngOnInit() {
    this.newList = {
        title: '',
        category:'',
        description:'',
        _id:''

    }
  }

  public onSubmit() {
    this.listServ.addList(this.newList).subscribe(
        response=> {
            if(response.success== true)
               //If success, update the view-list component
        },
    );

    }
}

Inside onSubmit(), we call the listService’s addList method that submits an http.post request to the server. Let's update our list service to make this happen.

/*list.service.ts*/

public addList(list: List) {
        let URI = `${this.serverApi}/bucketlist/`;
        let headers = new Headers;
         let body = JSON.stringify({title: list.title, description: 
            ➥list.description, category: list.category});
         console.log(body);
        headers.append('Content-Type', 'application/json');
        return this.http.post(URI, body ,{headers: headers})
        .map(res => res.json());
    }
}

If the server returns { success: true }, we need to update our lists and incorporate the new list into our table.

However, the challenge here is that the lists property resides inside the ViewList component. We need to notify the parent component that the list needs to be updated via an event. We use EventEmitter and the @Output decorator to make this happen.

First, you need to import Output and EventEmitter from @angular/core.

import { Component, OnInit, Output, EventEmitter } from '@angular/core';

Next, declare EventEmitter with the @Output decorator.

@Output() addList: EventEmitter<List> = new EventEmitter<List>();

If the server returns success: true, emit the addList event.

public onSubmit() {
    console.log(this.newList.category);
    this.listServ.addList(this.newList).subscribe(
        response=> {
            console.log(response);
            if(response.success== true)
                this.addList.emit(this.newList);
        },
    );

}

Update your viewlist.component.html with this code.

<app-add-list (addList)='onAddList($event)'> </app-add-list>

And finally, add a method named onAddList() that concatenates the newly added list into the lists property.

public onAddList(newList) {
    this.lists = this.lists.concat(newList);
}

Finishing Touches

I've added some styles from bootswatch.com to make our bucket list app look awesome.

Build your application using:

ng build

As previously mentioned, the build artifacts will be stored in the public directory. Run npm start from the root directory of the MEAN project. You should now have a working MEAN stack application up and running at http://localhost:3000/

Wrapping It Up

We’ve covered a lot of ground in this tutorial, creating a MEAN stack application from scratch. Here’s a summary of what we did in this tutorial. We:

  • created the back end of the MEAN application using Express and MongoDB
  • wrote code for the GET/POST and DELETE routes
  • generated a new Angular project using Angular CLI
  • designed two new components, AddList and ViewList
  • implemented the application's service that hosts the server communication logic.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset