Angular 9 Nodejs MongoDB CRUD Example – using Express RestAPIs + Mongoose ODM Queries Tutorial

Angular 9 Nodejs MongDB Crud Examples

In the tutorial, I introduce how to build an “Angular 9 Nodejs MongoDB CRUD Example RestAPIs” project with the help of Express Web Framework and Mongoose ODM for POST/GET/PUT/DELETE requests with step by step coding examples:

– I draw a fullstack overview Diagram Architecture from Angular 9 Frontend to MongoDB database through Nodejs RestAPI backend.
– Develop Nodejs CRUD RestAPIs with the supporting of Express Rest Framework.
– Implement Angular 9 CRUD application with the Angular 9 Httpclient to do CRUD request (Post/Get/Put/Delete) to Nodejs Backend APIs.
– I create a testsuite with a number of integrative testcases with CRUD RestAPI requests from Angular 9 HttpClient to do CRUD requests to Nodejs RestAPIs Server and save/retrieve data to MongoDB database.

Related posts:


What will we do?


Overview Example – How to build Angular 9 MongoDB Nodejs CRUD Example?

Overall Architecture System: Angular 9 + Nodejs + MongoDB

Angular 9 Nodejs MongoDB Diagram Architecture
Angular 9 Nodejs MongoDB Diagram Architecture
  • We build a backend: Nodejs CRUD Express Mongoose Application with MongoDB Atlas that provides RestAPIs for POST/GET/PUT/DELETE data entities and store them in MongoDB database.
  • We implement Angular 9 CRUD Application that use Angular 9 HTTPClient to interact (call/receive requests) with Nodejs CRUD application and display corresponding data in Angular Component.

Nodejs Express Mongoose CRUD Design Application

Nodejs Express MongoDB CRUD RestApis
Nodejs Express MongoDB CRUD RestApis

Our Nodejs CRUD Application has 4 main blocks:

  • To build RestAPIs in Node.js application, we use Express framework.
  • To do CRUD operations with MongoDB database, we use Mongoose ODM queries.
  • We define Nodejs RestAPI URLs in router.js file
  • We implement the logic: how to process each RestAPI in controller.js file
Nodejs MongoDB Crud Project Structure
Nodejs MongoDB Crud Project Structure
  • config package is used to configure MongoDB database environment
  • models package is used to define Mongoose schema model to interact with MongoDB database
  • routers package is used to define RestAPI’ URLs
  • controllers is used to implement Nodejs business logic to process each RestAPI

Angular 9 HttpClient CRUD Application Design

Angular 9 Application Diagram Architecture CRUD Nodejs RestAPIs
Angular 9 Application Diagram Architecture CRUD Nodejs RestAPIs

– Angular 9 CRUD Application is designed with 3 main layers:

  • Service Layer is used to define Angular 9 Common Services and Angular HttpClient Services to do CRUD requests with Nodejs RestAPIs
  • Component Layer is used to define Angular 9 Components to display views in Browser.
  • Router Layer is used to define all Angular navigation URLs mapping with the corresponding Angular Components
Angular 9 Nodejs CRUD RestAPIs Application Project Structure
Angular 9 Nodejs CRUD RestAPIs Application Project Structure

Angular CRUD Application defines 3 components, 2 services, 1 routers, and 2 data models:

– Angular Components:

  • add-customer component is used to post a new data to MongoDB via Nodejs RestAPI
  • list-customer component is used to display all data on views, delete a data and update a data with
    a given id to MongoDB using Nodejs RestAPIs: Get/Put/Delete
  • message component is used to define a view to show logging message on browser

– Angular Services:

  • customer.service.ts defines CRUD Angular httpclient post/get/put/delete requests to Node.js Express RestAPIs
  • message.service.ts defines an array storage to log all messages when the Angular 9 CRUD App running

– Angular Router: app-routing.module.ts defines how to map a corresponding Angular component with an URL.

– Models:

  • customer.ts defines the main data model of Angular application.
  • message.ts defines the response data model between Nodejs and Angular application.

Project Goal

– Angular adds a data:

Angular 9 Post request
Angular 9 Post request

– Angular Nodejs MongoDB list all data:

Angular 9 List all documents - Successfully
Angular 9 List all documents – Successfully

– Angular update a data:

Angular Update Document to MongoDB - Successfully
Angular Update Document to MongoDB – Successfully

– Delete a record:

Angular Delete a Document - successfully
Angular Delete a Document – successfully

– Check all MongoDB’s documents:

Check MongoDB documents after do CRUD requests
Check MongoDB documents after do CRUD requests

Nodejs MongoDB Atlas Express Mongoose CRUD RestAPIs Example – Backend Development

Create Nodejs Express Project

To development a ‘Node.js MongoDB CRUD Example with Mongoose and Express RestAPIs’, we need a set of packages to handle the full stack of the web backend proccessing, they includes Express framework, Cors, Body Parse, Mongoose packages.

  1. Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
    $ npm install express
    
  2. CORS is a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
    $ npm install cors
    
  3. Body-parser is the Node.js body parsing middleware. It is responsible for parsing incoming request bodies in a middleware before your handlers, available under the req.body property.
    $ npm install body-parser
    
  4. Mongoose is a promise-based Node.js ODM for MongoDB.
    $ npm install --save mongoose

We can install all the packages by one cmd:

$npm install --save express cors body-parser pg pg-hstore mongoose

Check package.json file is created as below content:


{
  "name": "nodejs-express-mongodb-crud-example",
  "version": "1.0.0",
  "description": "Nodejs Express CRUD RestAPIs with Mongoose Example",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/loizenai"
  },
  "keywords": [
    "nodejs",
    "crud",
    "restapi",
    "mongoose",
    "example",
    "express"
  ],
  "author": "https://loizenai.com",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "mongoose": "^5.10.2",
    "sequelize": "^6.3.4"
  }
}

MongoDB Atlas Configuration

We create a file mongodb.config.js as below:

module.exports = {
  url: 'mongodb+srv://loizenai:loizenai@cluster0.esvi3.mongodb.net/loizenaidb'
}

Define Mongoose Model

In the tutorial, ‘Angular 9 Node.js Express MongoDB RestAPIs Example’, We need define a Mongoose ODM model to represent a document in the customer collection, see details of coding in file customer.model.js:

const mongoose = require('mongoose');
 
const CustomerSchema = mongoose.Schema({
    firstname: String,
    lastname: String,
    address: String,
    age: { 
      type: Number, 
      min: 18, 
      max: 65, 
      required: true 
    },
    copyrightby: {
      type: String,
      default: 'https://loizenai.com'
    }
});

module.exports = mongoose.model('Customer', CustomerSchema);

Define Nodejs Express RestAPIs Router

I define 4 URLs for Nodejs CRUD RestAPIs with MongoDB:

  • /api/customers/create is Post restApi to do a post request
  • /api/customers/retrieveinfos is a Get restApi to retrieve all records from MongoDB
  • /api/customers/updatebyid/:id is a Put RestAPI to update a data by a given id
  • /api/customers/deletebyid/:id is a Delete RestApi to delete a data by a given id

– Detail Coding:

module.exports = function(app) {
 
  var customers = require('../controllers/customer.controller.js');

  // Create a new Customer
  app.post('/api/customer/create', customers.create);

  // Retrieve all Customer
  app.get('/api/customer/retrieveinfos', customers.findall);

  // Update a Customer with Id
  app.put('/api/customer/updatebyid/:id', customers.update);

  // Delete a Customer with Id
  app.delete('/api/customer/deletebyid/:id', customers.delete);
}

Implement Fullstack Nodejs Express Mongoose CRUD RestAPIs with MongoDB

To process CRUD Post/Get/Put/Delete RestAPI requests, we implement a file controller.js with 4 functions:

  • exports.create = (req, res) is used to create a new posting data to MongoDB (Nodejs Post request)
  • exports.retrieveInfos = (req, res) is used to retrieve all data’s infos from MongoDB database (Nodejs Get Request)
  • exports.updateById = async (req, res) is used to update a data from MongoDB with a given id (Nodejs PUT request)
  • exports.deleteById = async (req, res) is used to delete a customer with a given id (Nodejs Delete request)

Nodejs Post request

create = (req, res) function is used to handle a POST request at the endpoint /api/customer/create, save data to MongoDB database and return back a JSON message.

What will we do?

  • Create a Customer object from a request’s body data
  • Use the Mongoose Model to save created object to MongoDB database
  • Return back a JSON message to client side

Remember to use the catch statement for handling any error if having unexpected exception.

exports.create = (req, res) => {

    const customer = new Customer({
                          firstname: req.body.firstname,
                          lastname: req.body.lastname,
                          age: req.body.age,
                          address: req.body.address,
                        });
 
    // Save a Customer in the MongoDB
    customer.save().then(data => {
                    // send uploading message to client
                    res.status(200).json({
                      message: "Upload Successfully a Customer to MongoDB with id = " + data.id,
                      customer: data,
                    });
                }).catch(err => {
                    res.status(500).json({
                      message: "Fail!",
                      error: err.message
                    });
                });
};

Nodejs Get request

Now we implement fullstack from Nodejs Express GET request using Mongoose ODM to retrieve data from MongoDB database. We create a GET request methods: findall = (req, res) function is used to handle a GET request at the endpoint /api/customers/retrieveinfos to fetch all documents from MongoDB and return back to client in JSON format

How to implement findall = (req, res) function? It’s so simple

  • Using Customer.find() function to fetch all documents from MongoDB database
  • Return a JSON message to client with needed information
  • Do not forget to handle any unexpected error by using catch statement if having any exception throwed

exports.findall = (req, res) => {
    Customer.find().select('-__v').then(customerInfos => {
          res.status(200).json({
            message: "Get all Customers' Infos Successfully!",
            numberOfCustomers: customerInfos.length,
            customers: customerInfos
          });
        }).catch(error => {
          // log on console
          console.log(error);

          res.status(500).json({
              message: "Error!",
              error: error
          });
        });
};

Nodejs Delete request

exports.delete = (req, res) function is used to handle a DELETE request at the endpoint /api/customer/deletebyid/:id to delete a specific document from MongoDB database with a given id from the path parameter.

How to implement it?

  • Using the Mongoose Model’s function: findByIdAndRemove to check the existence of a specific document in MongoDB database with a given id: Customer.findByIdAndRemove(customerId)
  • If it does NOT existed, return a 404 NOT-FOUND message
  • Otherwise, the Mongoose model’s function: findByIdAndRemove will delete the document in MongoDB database then returns back a successfully message with 200 status code to client side
  • Do not forget to handle any unexpected error by using a catch statement

– Coding :


exports.delete = (req, res) => {
    let customerId = req.params.id

    Customer.findByIdAndRemove(customerId).select('-__v -_id')
        .then(customer => {
            if(!customer) {
              res.status(404).json({
                message: "Does Not exist a Customer with id = " + customerId,
                error: "404",
              });
            }
            res.status(200).json({
              message: "Delete Successfully a Customer with id = " + customerId,
              customer: customer,
            });
        }).catch(err => {
            return res.status(500).send({
              message: "Error -> Can NOT delete a customer with id = " + customerId,
              error: err.message
            });
        });
};

Nodejs Put request

Now we implement a fullstack solution: Nodejs Express RestAPI PUT request to get data from MongoDB using Mongoose ODM.

update = (req, res) function is used to handle a PUT request at the endpoint /api/customer/updatebyid/:id to update a specific document from MongoDB database with a given id

How to implement it? Just simple:

  • Use Mongoose ODM Model’s function: findByIdAndUpdate() to fetch a specific Customer with a given id from request parameter:
    Customer.findByIdAndUpdate(req.params.id, ...)
  • If existing a specific instance with the given id, it will update new values from body request to the founded Customer object and save the object again to MongoDB database, then returns back to client a Json message with 200 status code:
    res.status(200).json({
                  message: "Update successfully a Customer with id = " + req.params.id,
                  customer: customer,
                });
  • If not found a document with a given id, it will return back to client a Json message with 404 status code:
    if(!customer) {
                    return res.status(404).send({
                        message: "Error -> Can NOT update a customer with id = " + req.params.id,
                        error: "Not Found!"
                    });
                }
  • Don’t forget to use a catch statement to handle any unexpected-exception

– Coding:

exports.update = (req, res) => {
    // Find customer and update it
    Customer.findByIdAndUpdate(
                    req.params.id, 
                      {
                        firstname: req.body.firstname,
                        lastname: req.body.lastname,
                        age: req.body.age
                      }, 
                        {new: true}
                    ).select('-__v')
        .then(customer => {
            if(!customer) {
                return res.status(404).send({
                    message: "Error -> Can NOT update a customer with id = " + req.params.id,
                    error: "Not Found!"
                });
            }

            res.status(200).json({
              message: "Update successfully a Customer with id = " + req.params.id,
              customer: customer,
            });
        }).catch(err => {
            return res.status(500).send({
              message: "Error -> Can not update a customer with id = " + req.params.id,
              error: err.message
            });
        });
};

Create Nodejs Express Server with MongoDB Connection

To implement an Express RestAPIs Application, firstly we need create a server with express app:

server.js:

const express = require('express');
const app = express();
...
const server = app.listen(8080, function () {
 
  let host = server.address().address
  let port = server.address().port
 
  console.log("App listening at http://%s:%s", host, port); 
})

– For parsing body of requests, we need use body-parser dependency, add more code on server.js file:


...
var bodyParser = require('body-parser');
...
app.use(bodyParser.json());
...
const server = app.listen(8080, function () {
...
>

– To connect with MongoDB, we use below segment code:

mongoose.connect(dbConfig.url, { useNewUrlParser: true, useUnifiedTopology: true })
    .then(() => {
        console.log("Successfully connected to MongoDB.");    
    }).catch(err => {
        console.log('Could not connect to MongoDB.');
        process.exit();
    });

Here is all coding in the server.js file:

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json())

// Configuring the database
const dbConfig = require('./app/config/mongodb.config.js');
const mongoose = require('mongoose');
 
mongoose.Promise = global.Promise;
 
// Connecting to the database
mongoose.connect(dbConfig.url, { useNewUrlParser: true, useUnifiedTopology: true })
    .then(() => {
        console.log("Successfully connected to MongoDB.");    
    }).catch(err => {
        console.log('Could not connect to MongoDB.');
        process.exit();
    });

require('./app/routes/customer.router.js')(app);
// Create a Server
var server = app.listen(8080, function () { 
  var host = server.address().address
  var port = server.address().port
 
  console.log("App listening at http://%s:%s", host, port) 
})

Backend Testing: Nodejs MongoDB Express Mongoose CRUD RestAPIs

Testcase 1: Nodejs Post request

Nodejs Post request - post data to MongoDB
Nodejs Post request – post data to MongoDB

Check MongoDB documents:

All Documents in MongoDB after posting
All Documents in MongoDB after posting

Testcase 2: Nodejs Get request – Retrieve all records in MongoDB

Nodejs Get request - Retrieve all documents from MongoDB
Nodejs Get request – Retrieve all documents from MongoDB

Testcase 3: Nodejs Put request – Update a record by given id

Nodejs Update request - Update data to MongDB Atlas
Nodejs Update request – Update data to MongDB Atlas

– Check MongoDB document:

Update data to MongoDB
Update data to MongoDB

Testcase 4: Nodejs Delete request – Remove a record by given id

Nodejs Delete a Document from MongoDB via _id
Nodejs Delete a Document from MongoDB via _id

– Check MongoDB documents after doing CRUD requests:

Check MongoDB documents after do CRUD operations
Check MongoDB documents after do CRUD operations

Angular 9 CRUD Application Example – Frontend Development

Angular 9 CRUD Application Overview with Nodejs RestAPIs

Angular 9 Application Diagram Architecture CRUD Nodejs RestAPIs
Angular 9 Application Diagram Architecture CRUD Nodejs RestAPIs

– For more details, we go back to the session: Angular CRUD Design

Create Angular 9 Application

We create Angular 9 CRUD project by commandline: ng new AngularHttpclient.
– Create 3 components AddCustomer, ListCustomers, Message by cmd:


ng g component AddCustomer
ng g component ListCustomers
ng g component Message

– Create 2 Angular services CustomerService, MessageService by cmd:


ng g service customer
ng g service message

– Create 2 models Customer and Message by cmd:


ng g class customer;
ng g class message;

Create Angular Typescript Model

We define Customer class with 5 attributes:

export class Customer {
    id: number;
    firstname: string;
    lastname: string;
    age: number;
    address: string
}

Create Typescript Message

We define Message class as below:

import { Customer } from './customer';

export class Message {
    message: string;
    error: string;
    customers: Customer[];
}

Implement Angular 9 CRUD HttpClient Service

For interacting with Backend RestAPIs, we use Angular built-in Httpclient service:

@Injectable({
  providedIn: 'root'
})
export class CustomerService {

  private baseUrl = 'http://localhost:8080/api/customers';

  constructor(private http: HttpClient) { }
  
  ...

To handle Error, we implement a function private handleError(error: HttpErrorResponse):

private handleError(error: HttpErrorResponse) {
  if (error.error instanceof ErrorEvent) {
    // A client-side or network error occurred. Handle it accordingly.
    console.error('An error occurred:', error.error.message);
  } else {
    // The backend returned an unsuccessful response code.
    // The response body may contain clues as to what went wrong,
    console.error(
      `Backend returned code ${error.status}, ` +
      `body was: ${error.error}`);
  }
  // return an observable with a user-facing error message
  return throwError(
    'Something bad happened; please try again later.');
};

Angular 9 HttpClient Post request

createCustomer(customer: Customer): Observable<Message> {
    return this.http.post<Message>(`${this.baseUrl}` + `/create`, customer)
                .pipe(
                  retry(3),
                  catchError(this.handleError)
                );
}

– The above function posts a Customer to SpringBoot backend server at URL http://localhost:8080/api/customers/create
retry(3) is used to retry a failed request up to 3 times

Angular 9 HttpClient Get request

– Angular Client retrieve all data from MongoDB via Nodejs Express CRUD backend by a GET request at URL http://localhost:8080/api/customers/retrieveinfos.

retrieveAllCustomers(): Observable {
    return this.http.get(`${this.baseUrl}` + `/retrieveinfos`)
                  .pipe(
                    retry(3),
                    catchError(this.handleError)
                  );
}

Angular 9 HttpClient Put request

– Angular 9 client updates a data using Angular 9 built-in Httpclient by a PUT request at URL:
http://localhost:8080/api/customers/updatebyid/{id}

updateCustomer(customer: Customer): Observable<Message> {
    return this.http.put<Message> (`${this.baseUrl}` + `/updatebyid/` + customer.id, customer)
      .pipe(
          retry(3),
          catchError(this.handleError)
        );
}

Angular 9 HttpClient Delete request

– Angular 9 client deletes a data from MongoDB by a given id using built-in Angular Httpclient by a Delete request at URL:
http://localhost:8080/api/customers/deletebyid/{id}:


deleteCustomer(id: number): Observable<Message> {
    return this.http.delete<Message>(`${this.baseUrl}` + `/deletebyid/` + id)
          .pipe(
            retry(3),
            catchError(this.handleError)  
          );
}

Implement Angular 9 post/get/put/delete components

Implement Angular 9 Message Service

For tracking the proccessing of each step of Angular 9 CRUD Application, we implement a Message service to store tracing-logs message then display them on Html.

The message.service.ts has an string array messages to store tracing-log messages and 2 functions: add(message: string) and clear()

– Coding:


import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MessageService {
  messages: string[] = [];

  add(message: string) {
    this.messages.push(message);
  }

  clear(){
    this.messages = [];
  }
}

Implement Angular 9 Post Component: adding data

AddCustomerComponent is used to post a new data Customer to MongoDB via Nodejs CRUD Application server.
– We have 2 parts:

  • add-customer.component.ts file
  • add-cusomer.component.html file

1. add-customer.component.ts file

import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { CustomerService } from '../customer.service';
import { Message } from '../message';
import { MessageService } from '../message.service';

@Component({
  selector: 'app-add-customer',
  templateUrl: './add-customer.component.html'
})
export class AddCustomerComponent implements OnInit {
  customer: Customer;
  /**
   * Constructing Http Customer Service
   * @param customerService 
   */
  constructor(private customerService: CustomerService,
                private messageService: MessageService) { }

  ngOnInit(): void {
    this.customer = new Customer();
  }

  /**
   * Store a Customer to backend server
   */
  save() {
    this.customerService.createCustomer(this.customer)
          .subscribe((message: Message) => {
            console.log(message);
            let customer = message.customers[0];
            let msg = "Success -> Post a Customer: " 
                + "<ul>"
                    + "<li>id: " + customer.id + "</li>"  
                    + "<li>firstname: " + customer.firstname + "</li>"
                    + "<li>lastname: " + customer.lastname + "</li>"
                    + "<li>age: " + customer.age + "</li>"
                    + "<li>address: " + customer.address + "</li>"
                + "</ul>";

            this.messageService.add(msg);
          }, error => {
            console.log(error);
            let msg = "Error! -> Action Posting a Customer:" 
                      + "<ul>"
                        + "<li>id = " + this.customer.id + "</li>"  
                        + "<li>firstname = " + this.customer.firstname + "</li>"
                        + "<li>lastname = " + this.customer.lastname + "</li>"
                        + "<li>age = " + this.customer.age + "</li>"
                        + "<li>address = " + this.customer.address + "</li>"
                      + "</ul>";

            this.messageService.add(msg);
          });
  }

  reset(){
    this.customer = new Customer();
  }

  /**
   * Function handles form submitting
   */
  onSubmit() {
    this.save();
    this.reset();
  }
}

2. Implement add-customer.component.html view:

<h2>Create Customer</h2>
<div>
  <form (ngSubmit)="onSubmit()"> 
    <!-- First name -->   
    <div class="form-group">
      <label for="firstname">First Name:</label>
      <input type="text" class="form-control" placeholder="Enter Firstname" 
                id="firstname" required [(ngModel)]="customer.firstname" name="firstname">
    </div>
    <!-- Last name -->
    <div class="form-group">
        <label for="lastname">Last Name:</label>
        <input type="text" class="form-control" placeholder="Enter Lastname" 
                  id="lastname" required [(ngModel)]="customer.lastname" name="lastname">
    </div>  
    <!-- Address -->
    <div class="form-group">
        <label for="address">Address:</label>
        <input type="text" class="form-control" placeholder="Enter Address" 
                  id="address" required [(ngModel)]="customer.address" name="address">
    </div>        
    
    <!-- Age -->
    <div class="form-group">
      <label for="age">Age</label>
      <input type="number" class="form-control" placeholder="Enter Age" 
                  id="age" required [(ngModel)]="customer.age" name="age">
    </div>
 
    <button type="submit" class="btn btn-success">Submit</button>
  </form>
</div>
<app-message></app-message>

Implement Angular 9 List Component: retrieve all data

ListCustomersComponent has 4 main functions:

  • Show all Customers
  • Show details a Customers
  • Delete a Customer
  • Update a Customer

1. Implement list-customers.component.ts:

import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { MessageService } from '../message.service';
import { CustomerService } from '../customer.service';
import { Message } from '../message';

@Component({
  selector: 'app-list-customers',
  templateUrl: './list-customers.component.html'
})
export class ListCustomersComponent implements OnInit {

  customers: Array<Customer> = [];
  showCustomer: Customer;
  isSelected: boolean = false;
  deletedCustomer: Customer;
  returnedMessage: string;

  constructor(private customerService: CustomerService,
                private messageService: MessageService) { }

  setCustomerDetails(customer: Customer){
    this.isSelected=!this.isSelected;
    if(this.isSelected){
      this.showCustomer = customer;
    }else{
      this.showCustomer = undefined;
    }
  }

  /**
   * Set deletedCustomer and reset returnedMessage = undefined
   * @param deleteCustomer
   */
  prepareDeleteCustomer(deleteCustomer: Customer){
    //assign delete-Customer
    this.deletedCustomer = deleteCustomer;
    // reset returned-Message
    this.returnedMessage = undefined;
  }

  /**
   * Delete a Customer by ID
   */
  deleteCustomer(){

    console.log("--- Access delelteCustomer() function");

    this.customerService.deleteCustomer(this.deletedCustomer.id)
                      .subscribe((message: Message) => {
                          console.log(message);
                          // remove a deletedCustomer from customers list on view
                          this.customers = this.customers.filter(customer => {
                            return customer.id != this.deletedCustomer.id;
                          })

                          // set a showing message in delete modal
                          this.returnedMessage = message.message;

                          // just reset showCustomer for not showing on view
                          this.showCustomer = undefined;

                          // add the delete message to message app for showing
                          this.messageService.add(message.message);
                        },
                        (error) => {
                          console.log(error);
                          let errMsg: string = "Error! Details: " + error;
                          this.messageService.add(errMsg);
                        });
  }

  /**
   * Update Customer function
   */
  updateCustomer() {
    this.customerService.updateCustomer(this.showCustomer)
                      .subscribe((message: Message) => {
                        console.log(message);
                        // update customers list
                        this.customers.map(x => {
                          if(x.id == this.showCustomer.id){
                            x = this.showCustomer;
                          }
                        });

                        let msg: string = "Update Successfully! -> New Customer's properties: <br>"
                                          + "<ul>"
                                            + "<li>" + "id: " + this.showCustomer.id + "</li>"
                                            + "<li>" + "firstname: " + this.showCustomer.firstname + "</li>"
                                            + "<li>" +  "lastname: " + this.showCustomer.lastname + "</li>"
                                            + "<li>" +  "age: " + this.showCustomer.age + "</li>"
                                            + "<li>" +  "address: " + this.showCustomer.address + "</li>"
                                          + "</ul>";
                        this.messageService.add(msg);
                      }
                      , (error) => {
                        console.log(error);
                        let errMsg = "Update Fail ! Error = " + error;
                        this.messageService.add(errMsg);
                      });
  }

  /**
   * Retrieve all Customer from Backend
   */
  retrieveAllCustomers() {
    this.customerService.retrieveAllCustomers()
                  .subscribe((message: Message) => {
                    console.log(message);
                    this.customers = message.customers;
                  }
                  , (error) => {
                    console.log(error);
                  });
  }

  ngOnInit(): void {
    this.retrieveAllCustomers();
  }
}

2. Implement list-customers.component.html:

<div *ngIf="customers.length">
    <h3>Customers</h3>
    <br>
    <table class="table table-hover table-sm">
        <thead class="thead-dark">
          <tr>
            <th>Id</th>
            <th>Firstname</th>
            <th>Address</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
            <tr *ngFor="let customer of customers">
              <td>
                <button type="button" class="btn btn-primary" (click)="setCustomerDetails(customer)">
                  {{customer.id}}
                </button>
              </td>
              <td>{{customer.firstname}}</td>
              <td>{{customer.address}}</td>
              <td>
                <button type="button" class="btn btn-danger" 
                  data-toggle="modal" data-target="#delete-modal" 
                                (click)=prepareDeleteCustomer(customer) >&times;</button>
              </td>
            </tr>
        </tbody>
    </table>
</div>

<!-- The Modal -->
<div class="modal fade" id="delete-modal">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
    
    <!-- Modal Header -->
    <div class="modal-header">
      <h4 class="modal-title">Delete!</h4>
      <button type="button" class="close" data-dismiss="modal">&times;</button>
    </div>
    
    <!-- Modal body -->
    <div class="modal-body">
        <div *ngIf="deletedCustomer">
          <p [hidden] = "returnedMessage">
            Do you want delete a customer with id = {{deletedCustomer.id}}
          </p>
          <p [hidden] = "!returnedMessage">
            {{returnedMessage}}
          </p>
        </div>
    </div>
    
    <!-- Modal footer -->
    <div class="modal-footer">
      <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
      <button [hidden] = "returnedMessage" type="button" class="btn btn-danger" (click)="deleteCustomer()">Delete</button>
    </div>				
    </div>
  </div>
  </div>

<div *ngIf="showCustomer">
    <h3>Update Customer</h3>
    <form (ngSubmit)="updateCustomer()"> 
        <!-- ID -->   
        <div class="form-group">
          <label for="id">Id:</label>
          <input type="numer" class="form-control"
                    id="id" required [(ngModel)]="showCustomer.id" name="id" disabled>
        </div>      
        <!-- First name -->   
        <div class="form-group">
          <label for="firstname">First Name:</label>
          <input type="text" class="form-control" placeholder="Enter Firstname" 
                    id="firstname" required [(ngModel)]="showCustomer.firstname" name="firstname">
        </div>
        <!-- Last name -->
        <div class="form-group">
            <label for="lastname">Last Name:</label>
            <input type="text" class="form-control" placeholder="Enter Lastname" 
                      id="lastname" required [(ngModel)]="showCustomer.lastname" name="lastname">
        </div>  
        <!-- Address -->
        <div class="form-group">
            <label for="address">Address:</label>
            <input type="text" class="form-control" placeholder="Enter Address" 
                      id="address" required [(ngModel)]="showCustomer.address" name="address">
        </div>        
        
        <!-- Age -->
        <div class="form-group">
          <label for="age">Age</label>
          <input type="number" class="form-control" placeholder="Enter Age" 
                      id="age" required [(ngModel)]="showCustomer.age" name="age">
        </div>
     
        <button type="submit" class="btn btn-success">Update</button>
      </form>
</div>
<app-message></app-message>


<script>
  let pathname = window.location.pathname;
  if(pathname == ""){
      $(".nav .nav-item a:first").addClass("active");
      $(".nav .nav-item a:last").removeClass("active");
  } else if (pathname == "/customers") {
      $(".nav .nav-item a:last").addClass("active");
      $(".nav .nav-item a:first").removeClass("active");
  }
  alert("ok");
</script>

Implement Angular 9 Message Component

MessageComponent is used to show all tracing-log messages in html view.

1. Implement message.component.ts:

import { Component, OnInit } from '@angular/core';
import { MessageService } from '../message.service';

@Component({
  selector: 'app-message',
  templateUrl: './message.component.html'
})
export class MessageComponent {
  constructor(public messageService: MessageService) {}
}

2. Implement message.component.html:

<div *ngIf="messageService.messages.length">
    <h3>Messages</h3>
    <button type="button" class="btn btn-secondary" (click)="messageService.clear()">clear</button>
    <br>
    <ol>
      <li *ngFor='let message of messageService.messages'>
        <div [innerHTML]="message">
        </div>
      </li>
    </ol>
  </div>

Configure Angular 9 Routing Module

To handle the navigation from one view to the next, you use the Angular router. The router enables navigation by interpreting a browser URL as an instruction to change the view.

The following command uses the Angular CLI to generate a basic Angular app with an app routing module, called AppRoutingModule, which is an NgModule where you can configure your routes.

ng new routing-app --routing

How to Define a route? -> There are three fundamental building blocks to creating a route.

1. Import the AppRoutingModule into AppModule and add it to the imports array.
The Angular CLI performs this step for you. However, if you are creating an app manually or working with an existing, non-CLI app, verify that the imports and configuration are correct.


import { AppRoutingModule } from './app-routing.module';
...

@NgModule({
  declarations: [
	...
  ],
  imports: [
	...
    AppRoutingModule,
    ...
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

2. Define your routes in your Routes array for “Angular 9 Nodejs PostgreSQL CRUD Example”:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AddCustomerComponent } from './add-customer/add-customer.component';
import { ListCustomersComponent } from './list-customers/list-customers.component';

const routes: Routes = [
  { 
    path: '', 
    component: AddCustomerComponent 
  },
  { 
    path: 'customers', 
    component: ListCustomersComponent 
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

3. Add your routes to your application.
In the index.html file, we add below html code for navigating URL:


<nav class="navbar navbar-expand-sm bg-primary navbar-dark">
  <ul class="navbar-nav">
    <li class="nav-item" id="li_add_customer">
      <a class="nav-link" href="">Add Customer</a>
    </li>
    <li class="nav-item" id="li_list_customers">
      <a class="nav-link" href="/customers">List Customers</a>
    </li>
  </ul>
</nav>

Next, update your component template to include . This element informs Angular to update the application view with the component for the selected route. So in main component,open app.component.ts file, add the tag:


<router-outlet></router-outlet>

Modify Index.html View Page

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AngularHttpclient</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <!-- Latest compiled and minified CSS -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
  <!-- jQuery library -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <!-- Popper JS -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
  <!-- Latest compiled JavaScript -->
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
</head>
<body>
  <div class="container" >  
    <div class="col-sm-5" style="background-color: #ffffcc; margin:10px;padding:10px; border-radius: 5px">
      <nav class="navbar navbar-expand-sm bg-primary navbar-dark">
        <ul class="navbar-nav">
          <li class="nav-item" id="li_add_customer">
            <a class="nav-link" href="">Add Customer</a>
          </li>
          <li class="nav-item" id="li_list_customers">
            <a class="nav-link" href="/customers">List Customers</a>
          </li>
        </ul>
      </nav>
      <app-root></app-root>
    </div>
  </div>
  <script>
    $(document).ready(function() {
      (function(){
        let pathname = window.location.pathname;
        if(pathname == "/"){
            $("#li_add_customer").addClass("active");
            $("#li_list_customers").removeClass("active");
        } else if (pathname == "/customers") {
            $("#li_list_customers").addClass("active");
            $("#li_add_customer").removeClass("active");
        } 
      })();
    });
  </script>
</body>
</html>

Integrative Testing: Angular 9 Application with Nodejs CRUD RestAPIs + MongoDB

Okay, now we do a set of testcases for the tutorial: “Angular 9 Node.js MongoDB CRUD Example using Express and Mongoose ODM”.

Testcase 1: Angular 9 Post data to MongoDB

– Network Logging:

Testcase 1 - Angular 9 post data to Mongodb Atlas
Testcase 1 – Angular 9 post data to Mongodb Atlas

– Angular Post data:

Angular 9 Post request
Angular 9 Post request

– Angular Message Logs:

Angular 9 Post data - Message returned
Angular 9 Post data – Message returned

Testcase 2: Angular 9 Get All data from MongoDB

– Network Logging:

Angular 9 List all documents - Network logging
Angular 9 List all documents – Network logging

– Angular List documents:

Angular 9 List all documents - Successfully
Angular 9 List all documents – Successfully

Testcase 3: Angular 9 Put data to MongoDB

– Network Logging:

Angular 9 Update document to MongoDB - network logging
Angular 9 Update document to MongoDB – network logging

– Angular Update Successfully:

Angular 9 Update Document to MongoDB - Successfully
Angular 9 Update Document to MongoDB – Successfully

Testcase 4: Angular 9 Delete data from MongoDB

Angular 9 Delete a Document - successfully
Angular 9 Delete a Document – successfully

– Check MongoDB after doing CRUD requests:

Check MongoDB documents after do CRUD requests
Check MongoDB documents after do CRUD requests

Sourcecode

Below is clearly running sourcecode for the tutorial “Angular 9 Nodejs MongoDB CRUD Example with Mongoose ODM and Express framework”:

1. Nodejs Mongoose ODM CRUD Application

Nodejs-Express-MongoDB-CRUD-Example

2. Angular 9 CRUD Application:

AngularCrudApplication

– Github sourcecode for the tutorial: “Angular 9 Nodejs MongoDB CRUD Example”

1. Nodejs MongoDB CRUD Application:

Nodejs CRUD MongoDB Example

2. Angular 9 CRUD Application:

Angular 9 CRUD Application

Further Reading

Related posts:


Leave a Reply

Your email address will not be published. Required fields are marked *