Angular 12 Nodejs Bootstrap Crud example

Angular provides the HttpClient in @angular/common/http for front-end applications communicate with backend services. In the tutorial, we show how to build an Angular application that uses the HttpClient to make get/post/put/delete requests with Observable apis to Node.js RestAPIs.

Related posts:
Angular 12 Service – with Observable Data for Asynchronous Operation
Angular 12 Routing/Navigation – with Angular Router Service
Angular 12 Template Driven Form – NgModel for Two-Way Data Binding


  • Angular 12
  • RxJS 6
  • Bootstrap 4
  • Visual Studio Code – version 1.24.0
  • Nodejs – v8.11.3



We create 2 projects:

– Angular Client Project:

angular-6-http-client-node.js-rest-apis-post-get-put-delete +angular-project-structure

– Node.js RestAPIs project:

angular-6-http-client-node.js-rest-apis-post-get-put-delete + nodejs-restapi-project-structure


– Retrieve all customers from Node.js RestAPIs:

angular-6-http-client-node.js-rest-apis-post-get-put-delete + retrieve-all-datas

– Update a customer -> Change the firstname of first customer: ‘Joe’ to ‘Robert’.


-> result:


– Delete ‘Peter’ customer:


– Add a new customer:


-> result:


– Check final customer’s list:


Node.js RestAPIs

Node.js exposes 5 RestAPIs as below:

  •‘/api/customers’, customers.create);
  • router.get(‘/api/customers’, customers.findAll);
  • router.get(‘/api/customers/:id’, customers.findOne);
  • router.put(‘/api/customers’, customers.update);
  • router.delete(‘/api/customers/:id’, customers.delete);

– Configure cross-origin for Angular-Client which running at port: 4200.

const cors = require('cors')
const corsOptions = {
  origin: 'http://localhost:4200',
  optionsSuccessStatus: 200

Angular 12 HttpClient

Use Angular HttpClient APIs to do Get/Post/Put/Delete requests to Node.js RestAPIs:

// 1. GET All Customers from remote SpringBoot API <code>@GetMapping(value="/api/customers")
getCustomers (): Observable<Customer[]> {
	return this.http.get<Customer[]>(this.customersUrl)
// 2. GET a Customer from remote SpringBoot API <code>@GetMapping(value="/api/customers/{id}")
getCustomer(id: number): Observable<Customer> {
	const url = `${this.customersUrl}/${id}`;
	return this.http.get<Customer>(url);
// 3. POST a Customer to remote SpringBoot API <code>@PostMapping(value="/api/customers")
addCustomer (customer: Customer): Observable<Customer> {
	return<Customer>(this.customersUrl, customer, httpOptions);
// 4.DELETE a Customer from remote SpringBoot API <code>@DeleteMapping(value="/api/customers/{id}")
deleteCustomer (customer: Customer | number): Observable<Customer> {
	const id = typeof customer === 'number' ? customer :;
	const url = `${this.customersUrl}/${id}`;
	return this.http.delete<Customer>(url, httpOptions);
// 5. PUT a Customer to remote SpringBoot API <code>@PutMapping(value="/api/customers")
updateCustomer (customer: Customer): Observable<any> {
	return this.http.put(this.customersUrl, customer, httpOptions);


Node.js RestAPIs

Setup Node.js/Express project

Create application directory:

mkdir nodejs-restapi
cd nodejs-restapi

Use the npm init to create ‘package.json’ file:

nodejs-restapi>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install ` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (nodejs-restapi)
version: (1.0.0)
description: Node.js RestAPI - GET/POST/PUT/DELETE
entry point: (index.js) server.js
test command:
git repository:
keywords: Node.js,RestAPI,
license: (ISC)
About to write to C:\workspace\nodejs-restapi\package.json:

  "name": "nodejs-restapi",
  "version": "1.0.0",
  "description": "Node.js RestAPI - GET/POST/PUT/DELETE",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  "keywords": [
  "author": "",
  "license": "ISC"

Is this OK? (yes) yes

-> Check content of ‘package.json’ file:

  "name": "nodejs-restapi",
  "version": "1.0.0",
  "description": "Node.js RestAPI - GET/POST/PUT/DELETE",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  "keywords": [
  "author": "",
  "license": "ISC"

We need express, body-parse and cors modules.
– Express is one of the most popular web frameworks for NodeJs which is built on top of Node.js http module, and adds support for routing, middleware, view system etc.
– Body-parser: parses/extract the body of an incoming HTTP request.
– Cors: a mechanism that uses HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin.

-> Installing them as commandline npm install express body-parser cors--save :

angular-6-http-client-node.js-rest-apis-post-get-put-delete + install-expres-body-parse-cors-package

-> see ‘package.json’ file:

  "name": "nodejs-restapi",
  "version": "1.0.0",
  "description": "Node.js RestAPI - GET/POST/PUT/DELETE",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  "keywords": [
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.18.3",
    "cors": "^2.8.4",
    "express": "^4.16.3"

Implement Node.js/Express RestAPIs

– In root folder ‘nodejs-restapi’, create a ‘server.js’ file:

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

const cors = require('cors')
const corsOptions = {
  origin: 'http://localhost:4200',
  optionsSuccessStatus: 200

let customerRouter = require('./app/routes/customer.routes.js');
app.use('/', customerRouter);

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

Implement Express Application ->

In root folder ‘nodejs-restapi’, create a router folder ‘/app/routes’. Then create a file ‘/app/routes/customer.routes.js’ for routing requests ‘GET/POST/DELETE/UPDATE’:

let express = require('express');
let router = express.Router();

let customers = require('../controllers/customer.controller.js');

// Create a new Customer'/api/customers', customers.create);

// Retrieve all Customer
router.get('/api/customers', customers.findAll);

// Retrieve a single Customer by Id
router.get('/api/customers/:id', customers.findOne);

// Update a Customer with Id
router.put('/api/customers', customers.update);

// Delete a Customer with Id
router.delete('/api/customers/:id', customers.delete);

module.exports = router;

In root folder ‘nodejs-restapi’, create a controller folder ‘/app/controllers’. Then create a file ‘/app/controllers/customer.controller.js’ that contains methods for executing above URL requests:

let customers = {
				customer1: {
					id: 1,
					firstname: "Joe",
					lastname: "Thomas",
					age: 36
				customer2: {
					id: 2,
					firstname: "Peter",
					lastname: "Smith",
					age: 18
				customer3: {
					id: 3,
					firstname: "Lauren",
					lastname: "Taylor",
					age: 31
				customer4: {
					id: 4,
					firstname: "Mary",
					lastname: "Taylor",
					age: 24
				customer5: {
					id: 5,
					firstname: "David",
					lastname: "Moore",
					age: 25
				customer6: {
					id: 6,
					firstname: "Holly",
					lastname: "Davies",
					age: 27
				customer7: {
					id: 7,
					firstname: "Michael",
					lastname: "Brown",
					age: 45
exports.create = function(req, res) {
	// find the largest ID
	let arr = Object.keys( customers ).map(function ( key ) { return customers[key].id; });
	let newId = Math.max.apply( null, arr ) + 1;
	let newCustomer = req.body; = newId;
    customers["customer" + newId] = newCustomer;
exports.findAll = function(req, res) {
exports.findOne = function(req, res) {
    let customer = customers["customer" +];
exports.update = function(req, res) {
	let updatedCustomer = req.body; 
	customers["customer" +] = updatedCustomer;
	res.json({msg: "Customer Updated Successfully!"});
exports.delete = function(req, res) {
    delete customers["customer" +];
    res.json({msg: "Customer Deleted Successfully!"});

Angular 12 Client

– Create Angular project:

ng new angular6-httpclient

– Generate:

  • Customer Class
  • Customer Service
  • Customer Components
  • App Routing Module

-> Details:

ng generate class Customer
ng generate service Customer
ng generate component Customer
ng generate component CustomerDetails
ng generate component AddCustomer
ng generate module AppRouting

– Install Bootstrap 4:

npm install bootstrap jquery --save

-> Configure installed Bootstrap & JQuery in angular.json file:

"styles": [
"scripts": [

Data Model

Implement Customer model customer.ts :

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

Configure AppModule

In the developed application, we use:

  • Angular Forms -> for building form
  • HttpClient -> for http Get/Post/Put/Delete requests
  • AppRouting -> for app routing

-> Modify AppModule app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule }   from '@angular/forms';
import { HttpClientModule }    from '@angular/common/http';
import { AppRoutingModule }     from './app-routing/app-routing.module';
import { AppComponent } from './app.component';
import { CustomerComponent } from './customer/customer.component';
import { CustomerDetailsComponent } from './customer-details/customer-details.component';
import { AddCustomerComponent } from './add-customer/add-customer.component';
  declarations: [
  imports: [
  providers: [],
  bootstrap: [AppComponent]
export class AppModule { }

HttpClient DataService

Implement CustomerService customer.service.ts with HttpClient for Get/Post/Put/Delete:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Customer } from './customer';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })

  providedIn: 'root'
export class CustomerService {
  private customersUrl = 'http://localhost:8080/api/customers';  // URL to web api
    private http: HttpClient
  ) { }

  getCustomers (): Observable {
    return this.http.get(this.customersUrl)

  getCustomer(id: number): Observable {
    const url = `${this.customersUrl}/${id}`;
    return this.http.get(url);

  addCustomer (customer: Customer): Observable {
    return, customer, httpOptions);

  deleteCustomer (customer: Customer | number): Observable {
    const id = typeof customer === 'number' ? customer :;
    const url = `${this.customersUrl}/${id}`;

    return this.http.delete(url, httpOptions);

  updateCustomer (customer: Customer): Observable {
    return this.http.put(this.customersUrl, customer, httpOptions);

Angular Router

Implement App-Routing module app-routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomerComponent } from '../customer/customer.component';
import { AddCustomerComponent } from '../add-customer/add-customer.component';
import { CustomerDetailsComponent } from '../customer-details/customer-details.component';
const routes: Routes = [
     path: 'customers', 
     component: CustomerComponent 
     path: 'customer/add', 
     component: AddCustomerComponent 
     path: 'customers/:id', 
     component: CustomerDetailsComponent 
     path: '', 
     redirectTo: 'customers', 
     pathMatch: 'full'
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
export class AppRoutingModule {}

Router Outlet & Router Links

-> Questions:

  • How to show Componenets with Angular Routers? -> Solution: using Router Outlet
  • How to handle the routing that comes from user’s actions? (like clicks on anchor tag) -> Solution: using Router Link

-> We can achieve above functions by using Angular’s router-outlet and routerLink.

Modify the template file app.component.html of AppComponenet component as below:

<div class="container">
  <div class="row">
    <div class="col-sm-4">  
      <h1>Angular HttpClient</h1>
      <ul class="nav justify-content-center">
          <li class="nav-item">
              <a routerLink="customers" class="btn btn-light btn-sm" role="button" routerLinkActive="active">Retrieve</a> 
          <li class="nav-item">
              <a routerLink="customer/add" class="btn btn-light btn-sm" role="button" routerLinkActive="active">Create</a>

Customer Component

customer Component ->


– Implement CustomerComponent class customer.component.ts:

import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { CustomerService } from '../customer.service';
  selector: 'app-customer',
  templateUrl: './customer.component.html',
  styleUrls: ['./customer.component.css']
export class CustomerComponent  implements OnInit {
  customers: Customer[];
  constructor(private customerService: CustomerService) {}
  ngOnInit(): void {
  getCustomers() {
    return this.customerService.getCustomers()
                 customers => {
                  this.customers = customers

– Implement the template customer.component.html :

<h5>All Customers</h5>
<div *ngFor="let cust of customers">
  <a [routerLink]="['/customers',]" style="color:black"><span class="badge badge-dark">{{}}</span> -> {{ cust.firstname }}</a>

Customer Detail Component

Customer Detail ->


-> results:



– Implement CustomerDetails class customer-details.component.ts:

import { Component, OnInit } from '@angular/core';
import { Customer } from '../customer';
import { CustomerService } from '../customer.service';
import { ActivatedRoute, Params } from '@angular/router';
import { Location } from '@angular/common';
  selector: 'app-customer-details',
  templateUrl: './customer-details.component.html',
  styleUrls: ['./customer-details.component.css']
export class CustomerDetailsComponent implements OnInit {
  customer = new Customer() ;
  submitted = false;
  message: string;
    private customerService: CustomerService,
    private route: ActivatedRoute,
    private location: Location
  ) {}
  ngOnInit(): void {
    const id = +this.route.snapshot.paramMap.get('id');
      .subscribe(customer => this.customer = customer);
  update(): void {
    this.submitted = true;
        .subscribe(() => this.message = "Customer Updated Successfully!");
  delete(): void {
    this.submitted = true;
        .subscribe(()=> this.message = "Customer Deleted Successfully!");
  goBack(): void {

– Implement CustomerDetailsComponent template customer-details.component.html :

<h4><span class="badge badge-light ">{{}}</span> -> {{customer.firstname}}</h4>
<div [hidden]="submitted">
    <form (ngSubmit)="update()" #detailCustomerForm="ngForm">
      <div class="form-group">
        <label for="firstname">First Name</label>
        <input type="text" class="form-control" id="firstname" required
        [(ngModel)]="customer.firstname" name="firstname" #firstname="ngModel">
        <div [hidden]="firstname.valid || firstname.pristine"
             class="alert alert-danger">
            First Name is required
      <div class="form-group">
        <label for="lastname">Last Name</label>
        <input type="text" class="form-control" id="lastname" required
        [(ngModel)]="customer.lastname" name="lastname" #lastname="ngModel">
        <div [hidden]="lastname.valid || lastname.pristine"
             class="alert alert-danger">
            Last Name is required
      <div class="form-group">
        <label for="age">Age</label>
        <input type="number" class="form-control" id="age" required
        [(ngModel)]="customer.age" name="age" #age="ngModel">
        <div [hidden]="age.valid || age.pristine"
             class="alert alert-danger">
            Age is required

      <div class="btn-group btn-group-sm">
        <button type="button" class="btn btn-dark" (click)="goBack()">Back</button>
        <button type="submit" class="btn btn-dark" (click)="update()" [disabled]="!detailCustomerForm.form.valid">Update</button>
        <button type="button" class="btn btn-dark" (click)="delete()">Delete</button>
<div [hidden]="!submitted">
    <div class="btn-group btn-group-sm">
      <button type="button" class="btn btn-dark" (click)="goBack()">Back</button>

We can change the value of ng-valid & ng-invalid for more visual feedback,
-> Create ./assets/forms.css file:

.ng-valid[required], .ng-valid.required  {
    border-left: 5px solid rgba(32, 77, 32, 0.623);
.ng-invalid:not(form)  {
    border-left: 5px solid rgb(148, 27, 27);

Add ./assets/forms.css file to index.html :

<!doctype html>
<html lang="en">
  <meta charset="utf-8">
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" href="assets/forms.css">

Add-Customer Component

AddCustomer Component ->


-> result:


– Implement AddCustomerComponent class add-customer.component.ts:

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

import { Location } from '@angular/common';

  selector: 'app-add-customer',
  templateUrl: './add-customer.component.html',
  styleUrls: ['./add-customer.component.css']

export class AddCustomerComponent{

  customer = new Customer();
  submitted = false;

    private customerService: CustomerService,
    private location: Location
  ) { }

  newCustomer(): void {
    this.submitted = false;
    this.customer = new Customer();

 addCustomer() {
   this.submitted = true;;

  goBack(): void {

  private save(): void {

– Implement the template add-customer.component.html:



29 thoughts on “Angular 12 Nodejs Bootstrap Crud example”

  1. Just wish to say your article iis as surprising. The clarity in your sᥙƅmit is
    simply great and that i could assume you are a professional
    in this subject. Fine with your permission alⅼow me to clutch your feed to keeⲣ pdated wih
    coming near near pօst. Thank yօu one mіllion and please keeⲣ up the enjoyable work.

  2. Hey! I know this is somewhat off topic but I was wondering
    if you knew where I could find a captcha plugin for my comment form?
    I’m using the same blog platform as yours and I’m having trouble finding one?
    Thanks a lot!

  3. We are a gaggle of volunteers and starting a new scheme in our community.
    Your website provided us with helpful information to work on. You have performed a formidable
    process and our whole group can be grateful to you.

  4. Pretty great post. I simply stumbled upon your blog and wanted
    to say that I have really enjoyed browsing your
    weblog posts. After all I’ll be subscribing
    for your feed and I hope you write once more very soon!

  5. I’m now not certain the place you are getting your information, but good topic.
    I needs to spend some time finding out more or working out more.
    Thanks for wonderful info I was on the lookout for this info for my mission.

  6. Does your website have a contact page? I’m having a tough time locating
    it but, I’d like to send you an e-mail. I’ve got some creative ideas for your blog you might be interested in hearing.
    Either way, great website and I look forward to
    seeing it develop over time.

  7. Heya outstandіng bloɡ! Does running a blog similar tto this гequiгe a massive amount
    woгk? I have very lіttle expertise in computer programming but I
    had beеn hoping to start my own blog in the near future.
    Anywаys, if you have any recommendɑtions or techniques for new blog owneгs please sһare.
    I know thgis іs off subject howevеr I ust needed to ask.
    Appreciate it!

  8. Excellent pieces. Keep posting such kind of information on your site.
    Im really impressed by your site.
    Hello there, You have done a great job. I will certainly digg it and personally
    recommend to my friends. I am sure they’ll be benefited from this web site.

  9. Aw, this was an exceptionally good post. Taking a few minutes and actual effort to make
    a superb article… but what can I say… I hesitate a lot and don’t manage to get anything done.

  10. It’s ɑ pity you don’t have a donate button! I’ԁ certainly ɗonate to this brilliant blog!
    I suppose for now i’ll settle for book-marking and adding youг RSS feed to my Google account.

    I look forward to new updates annd ᴡiⅼl talk about thіs
    website witһ myy Facebook group. Chat soon!

  11. Pгetty nice post. I just stfumbled upon your
    weblog and ᴡished to say that I’ve truly enjoyed Ƅrowsing yⲟur boog posts.
    In any case I’llbe suƄscribіng to youг rsss feed and I hope yo᧐ս write agvain very soon!

  12. An impressive share! I’ve just forwarded this onto a co-worker who had been conducting
    a little homework on this. And he in fact bought me lunch simply because I found it for him…

    lol. So let me reword this…. Thanks for the
    meal!! But yeah, thanx for spending time to discuss this issue here on your web page.

  13. This is a great tip especially to those fresh to the blogosphere.
    Simple but very accurate information… Appreciate your sharing this one.
    A must read post!

  14. Howdy! Tһiѕ post could not Ьe written anyy better!

    Reading throuցh this post reminds me of mmy previous room
    mate! He always kept chatting about this. I will forward this writе-up too him.

    Pretty sure he will have a good read. Many thankks for sharіng!

  15. Having read this I believed it was very informative. I appreciate you spending some time and effort to put this information together.
    I once again find myself spending way too much time both reading and leaving comments.
    But so what, it was still worthwhile!

  16. Howdy very nice website!! Man .. Excellent .. Amazing ..
    I will bookmark your website and take the feeds
    also? I am glad to find so many helpful info here within the post, we’d like work
    out extra techniques on this regard, thank you for sharing.
    . . . . .

  17. Hi my friend! I want to say that this article is
    amazing, nice written and come with almost all vital infos.

    I would like to look more posts like this .

  18. I’m extremely impressed with your writing skills and also with the layout
    on your blog. Is this a paid theme or did you customize
    it yourself? Anyway keep up the excellent quality writing, it’s rare to
    see a great blog like this one today.

  19. I like the helpful information you provide in your articles.
    I’ll bookmark your weblog and check again here regularly.
    I am quite sure I’ll learn many new stuff right here!
    Good luck for the next!

  20. I think this is one of the most significant info for me. And i’m glad reading your article.
    But wanna remark on few general things, The web site style
    is wonderful, the articles is really excellent : D.
    Good job, cheers

Leave a Reply

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