Angular 9 Node.js PostgreSQL CRUD Example – Express RestAPIs + Sequelize ORM

Angular 9 PostgreSQL Nodejs CRUD Examples with Express RestAPIs and Sequelize ORM Queries

Tutorial: Angular 9 Node.js PostgreSQL CRUD Example – Express RestAPIs + Sequelize ORM

In the tutorial, I introduce how to build an Angular 9 Nodejs PostgreSQL CRUD Example RestAPIs project with the help of Express Web Framework and Sequelize ORM for POST/GET/PUT/DELETE requests with step by step coding examples.

Related posts:


What will we do?


Overview Example – How to build Angular 9 Node.js PostgreSQL CRUD Example?

Overall Architecture System: Angular 9 + Nodejs + PostgreSQL

Fullstack Architecture Angular 8 PostgreSQL Nodejs CRUD RestAPIs Application
Fullstack Architecture Angular 8 PostgreSQL Nodejs CRUD RestAPIs Application
  • We build a backend: Nodejs CRUD Express Sequelize Application with PostgreSQL that provides RestAPIs for POST/GET/PUT/DELETE data entities and store them in PostgreSQL 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 Sequelize CRUD Design Application

Architecture Overview Nodejs Express Sequelize PostgreSQL CRUD RestAPIs Application
Architecture Overview Nodejs Express Sequelize PostgreSQL CRUD RestAPIs Application

Our Nodejs CRUD Application has 4 main blocks:

  • To build RestAPIs in Node.js application, we use Express framework.
  • To do CURD operations with PostgreSQL database, we use Sequelize ORM queries.
  • We define Nodejs RestAPI URLs in router.js file
  • We implement the logic: how to process each RestAPI in controller.js file
Nodejs CRUD Application Project Structure
Nodejs CRUD Application Project Structure
  • config package is used to configure Sequelize and PostgreSQL database environment
  • models package is used to define Sequelize data model to interact with PostgreSQL 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 Architecture CRUD Nodejs RestAPIs
Angular 9 Application Architecture CRUD Nodejs RestAPIs

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

  • Service Layer is used to define Angular Common Services and Angular HttpClient Services to do CRUD requests with Nodejs RestAPIs
  • Component Layer is used to define Angular 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 PostgreSQL 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 PostgreSQL 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 Nodejs CRUD application adds a data
Angular 9 Nodejs CRUD application adds a data

– Angular Nodejs PostgreSQL list all data:

Angular 9 Nodejs CRUD Application list all data
Angular 9 Nodejs CRUD Application list all data

– Details a data:

Angular 9 Nodejs CRUD App details a data
Angular 9 Nodejs CRUD App details a data

– Angular update a data:

Angular 9 Nodejs CRUD Application update a data
Angular 9 Nodejs CRUD Application update a data

– Delete a record:

Angular 9 Nodejs CRUD App - delete a data with the given id
Angular 9 Nodejs CRUD App – delete a data with the given id

– Check database records:

Check PostgreSQL database
Check PostgreSQL database

Nodejs Express Sequelize CRUD RestAPIs Example – Backend Development

Create Nodejs Express Project

For building Nodejs Express Sequelize CRUD RestAPIs Application with PostgreSQL, we need to use the below dependencies:

  • body-parser is used to parse a submit form to Nodejs Express server.
  • express is used to build Nodejs CRUD RestAPIs
  • pg and pg-hstore is used to interact with PostgreSQL database as database driver
  • sequelize is used to do CRUD queries with PostgreSQL database
  • cors is a Node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options

We install them with below commandline:

npm install --save body-parse express pg pg-hstore sequelize cors

Check the Nodejs package.json file:

{
  "name": "nodejs-postgresql-crud-restapis-example",
  "version": "1.0.0",
  "description": "Nodejs PostgreSQL CRUD Application Post/Get/Put/Delete",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "Nodejs",
    "RestAPI",
    "Express",
    "Tutorial",
    "PostgreSQL"
  ],
  "author": "https://loizenjava.com",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "pg": "^8.3.2",
    "pg-hstore": "^2.3.3",
    "sequelize": "^5.21.13"
  }
}

Sequelize PostgreSQL Configuration

We define a db.config.js file to configure Sequelize PostgreSQL to do CRUD operations with PostgreSQL database:


const env = require('./env.js');
 
const Sequelize = require('sequelize');
const sequelize = new Sequelize(env.database, env.username, env.password, {
  host: env.host,
  dialect: env.dialect,
  operatorsAliases: false,
 
  pool: {
    max: env.max,
    min: env.pool.min,
    acquire: env.pool.acquire,
    idle: env.pool.idle
  }
});
 
const db = {};
 
db.Sequelize = Sequelize;
db.sequelize = sequelize;
 
db.Customer = require('../models/customer.model.js')(sequelize, Sequelize);
 
module.exports = db;

– For PostgreSQL database, we add the below configured environment’s properties in env.js


const env = {
  database: 'loizenjava',
  username: 'postgres',
  password: '123',
  host: 'localhost',
  dialect: 'postgres',
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  }
};
 
module.exports = env;

Define Sequelize Model

I create a Sequelize model customer.model.js to define a Customer entity with 5 properties:

  • id is a primary key having INTEGER type
  • firstname property has STRING type
  • lastname property has STRING type
  • address property has STRING type
  • age property has INTEGER type
module.exports = (sequelize, Sequelize) => {
	const Customer = sequelize.define('customer', {	
	  id: {
            type: Sequelize.INTEGER,
            autoIncrement: true,
            primaryKey: true
      },
	  firstname: {
			type: Sequelize.STRING
	  },
	  lastname: {
		type: Sequelize.STRING
  	  },
	  address: {
			type: Sequelize.STRING
	  },
	  age: {
			type: Sequelize.INTEGER
	  }
	});
	
	return Customer;
}

Define Nodejs Express RestAPIs Router

I define 4 URLs for Nodejs CRUD RestAPIs with PostgreSQL:

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

– Detail Coding:

let express = require('express');
let router = express.Router();
 
const customers = require('../controllers/controller.js');

router.post('/api/customers/create', customers.create);
router.get('/api/customers/retrieveinfos', customers.retrieveAllCustomers);
router.put('/api/customers/updatebyid/:id', customers.updateById);
router.delete('/api/customers/deletebyid/:id', customers.deleteById);

module.exports = router;

Implement Fullstack Nodejs Express Sequelize CRUD RestAPIs with PostgreSQL

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 PostgreSQL (Nodejs Post request)
  • exports.retrieveInfos = (req, res) is used to retrieve all data’s infos from PostgreSQL database (Nodejs Get Request)
  • exports.updateById = async (req, res) is used to update a data from PostgreSQL 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

exports.create = (req, res) => {
    let customer = {};

    try{
        // Building Customer object from upoading request's body
        customer.firstname = req.body.firstname;
        customer.lastname = req.body.lastname;
        customer.address = req.body.address;
        customer.age = req.body.age;
    
        // Save to MySQL database
        Customer.create(customer).then(result => {    
            // send uploading message to client
            res.status(200).json({
                message: "Upload Successfully a Customer with id = " + result.id,
                customers: [result],
                error: ""
            });
        });
    }catch(error){
        res.status(500).json({
            message: "Fail!",
            customers: [],
            error: error.message
        });
    }
}

exports.create = (req, res) – the function will get a posting data info via request.body object. Then it uses Sequelize ORM to save the customer object to PostgreSQL database. After done, it returns a successfully posting message. Otherwise, a error message will be returned.

Nodejs Get request – retrieve all data from PostgreSQL database

exports.retrieveInfos = (req, res) => {
    // find all Customer information from 
    try{
        Customer.findAll({attributes: ['id', 'firstname', 'address']})
        .then(customerInfos => {
            res.status(200).json({
                message: "Get Customers' Infos!",
                customerInfos: customerInfos
            });
        })
    }catch(error) {
        // log on console
        console.log(error);

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

The function exports.retrieveInfos = (req, res) retrieves all data from PostgreSQL database with 5 selected attributes: id, firstname, lastname, age, address.

Nodejs Delete request

exports.deleteById = async (req, res) => {
    try{
        let customerId = req.params.id;
        let customer = await Customer.findByPk(customerId);

        if(!customer){
            res.status(404).json({
                message: "Does Not exist a Customer with id = " + customerId,
                error: "404",
                customers: []
            });
        } else {
            await customer.destroy();
            res.status(200).json({
                message: "Delete Successfully a Customer with id = " + customerId,
                customers: [customer],
                error: ""
            });
        }
    } catch(error) {
        res.status(500).json({
            message: "Error -> Can NOT delete a customer with id = " + req.params.id,
            error: error.message,
            customers: []
        });
    }
}

The function exports.deleteById = async (req, res) finds a data from PostgreSQL database by a given id. If the record is found, it will be deleted by destroy() function and return back to Angular client a successfully message. Otherwise, an error message is returned.

Nodejs Put request

exports.updateById = async (req, res) => {
    try{
        let customerId = req.params.id;
        let customer = await Customer.findByPk(customerId);
    
        if(!customer){
            // return a response to client
            res.status(404).json({
                message: "Not Found for updating a customer with id = " + customerId,
                customers: [],
                error: "404"
            });
        } else {    
            // update new change to database
            let updatedObject = {
                firstname: req.body.firstname,
                lastname: req.body.lastname,
                address: req.body.address,
                age: req.body.age
            }
            let result = await Customer.update(updatedObject, {returning: true, where: {id: customerId}});
            
            // return the response to client
            if(!result) {
                res.status(500).json({
                    message: "Error -> Can not update a customer with id = " + req.params.id,
                    error: "Can NOT Updated",
                    customers: []
                });
            }

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

        });
    }
}

The function exports.updateById = async (req, res) finds a data from PostgreSQL by a given id. If the data is found, we change the data attributes with new values retrieving from request.body object. After done, a successfully message will be returned to Angular client. Otherwise an error message will be returned.

Create Nodejs Express Server

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 () {
...
>

We define all RESTAPI URLs in a file router.js and then need attach it with the Express Application:


...
let router = require('./app/routers/router.js');
...
app.use('/', router);
...
const server = app.listen(8080, function () {
...

To enable CORS function, we need attach it with Express app:

const cors = require('cors')
const corsOptions = {
  origin: 'http://localhost:4200',
  optionsSuccessStatus: 200
}
app.use(cors(corsOptions));

Here is all coding in the server.js file:

const express = require('express');
const app = express();

var bodyParser = require('body-parser');
 
const db = require('./app/config/db.config.js');
  
// force: true will drop the table if it already exists
db.sequelize.sync({force: true}).then(() => {
  console.log('Drop and Resync with { force: true }');
}); 

let router = require('./app/routers/router.js');

const cors = require('cors')
const corsOptions = {
  origin: 'http://localhost:4200',
  optionsSuccessStatus: 200
}
app.use(cors(corsOptions));

app.use(bodyParser.json());
app.use('/', router);

// Create a Server
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); 
})

Backend Testing: Nodejs Express Sequelize PostgreSQL CRUD RestAPIs

Testcase 1: Nodejs RestAPI Post request to PostgreSQL

Post a Customer to Nodejs CRUD application:

Postman post a data PostgreSQL via a post restapi of Nodejs Express Aplication
Postman post a data PostgreSQL via a post restapi of Nodejs Express Aplication

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

– Retrieve all customers:

Postman retrieve all data from PostgreSQL using GET RestAPIs of Nodejs Express Application
Postman retrieve all data from PostgreSQL using GET RestAPIs of Nodejs Express Application

Testcase 3: Nodejs Put request – Update a record in PostgreSQL

Postman update a record from PostgreSQL database using Nodejs CRUD RestAPI
Postman update a record from PostgreSQL database using Nodejs CRUD RestAPI

Testcase 4: Nodejs Delete request – Remove a record in PostgreSQL

Postman delete a PosgreSQL data with a given id via Nodejs Exprss RestAPI
Postman delete a PosgreSQL data with a given id via Nodejs Exprss RestAPI

Angular 9 CRUD Application Example – Frontend Development

Angular 9 CRUD Application Overview with Nodejs RestAPIs

Angular 9 CRUD Application Frontend Design Architecture
Angular 9 CRUD Application Frontend Design Architecture

– 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 PostgreSQL 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 HttpClient Put request

– Angular 9 client updates a data using Angular 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 PostgreSQL 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 PostgreSQL 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 + PostgreSQL

Okay, now we do a set of testcases for the tutorial: “Angular 9 Node.js PostgreSQL CRUD Example – Express RestAPIs + Sequelize ORM”.

Testcase 1: Angular 9 HttpClient Post data to PostgreSQL

Integrative Testing Angular 9 CRUD Application to PostgreSQL - Post Data via Nodejs Express Post request
Integrative Testing Angular 9 CRUD Application to PostgreSQL – Post Data via Nodejs Express Post request
Angular 9 CRUD Application - post a data successfully
Angular 9 CRUD Application – post a data successfully

Testcase 2: Angular 9 HttpClient Get All data from PostgreSQL

Testcase 2 - Integrative Testing Angular 9 CRUD Application - retrieve all data from PostgreSQL via Nodejs CRUD RestAPIs
Testcase 2 – Integrative Testing Angular 9 CRUD Application – retrieve all data from PostgreSQL via Nodejs CRUD RestAPIs
Angular 9 CRUD Application - display successfully retrieve data on view
Angular 9 CRUD Application – display successfully retrieve data on view

Testcase 3: Angular 9 HttpClient Put data to PostgreSQL

Testcase 3 - Angular 9 Update a Customer to PostgreSQL database via Nodejs Express PUT request
Testcase 3 – Angular 9 Update a Customer to PostgreSQL database via Nodejs Express PUT request
Angular 9 CRUD Application - Update data successfully to PostgreSQL database
Angular 9 CRUD Application – Update data successfully to PostgreSQL database

Testcase 4: Angular 9 HttpClient Delete data from PostgreSQL

Testcase 4 - Integrative testing Angular 9 - Delete a data via Nodejs Delete request
Testcase 4 – Integrative testing Angular 9 – Delete a data via Nodejs Delete request

Check PostgreSQL database:

Check PostgreSQL database after integrative testing between Angular 9 and Nodejs CRUD application
Check PostgreSQL database after integrative testing between Angular 9 and Nodejs CRUD application

Further Reading

Related posts:


Sourcecode

Below is clearly running sourcecode for the tutorial “Angular 9 Node.js PostgreSQL CRUD Example – Express RestAPIs + Sequelize ORM”:

1. Nodejs PostgreSQL CRUD Application

Nodejs PostgreSQL CRUD Application

2. Angular 9 CRUD Application:

AngularCrudApplication

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

1. Nodejs PostgreSQL CRUD Application:

Node.js PostgreSQL CRUD Application

2. Angular 9 CRUD Application:

Angular 9 CRUD Application

Leave a Reply

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