AppDividend
Latest Code Tutorials

Angular 7 CRUD Example | MEAN Stack Tutorial From Scratch

53

Angular 7 CRUD Example | MEAN Stack Tutorial is today’s leading topic. In this article, we will be creating a sample Angular 7 application step by step from scratch and perform CRUD operations. The backend API will be exposed using Node.js, and Express framework and MongoDB will be used for persistent storage of the data. We will be using Angular CLI 7 to generate the boilerplate project. This Angular 7 CRUD Example Tutorial is the comprehensive guide on building CRUD (Create, Read, Update, Delete) Web Application using the New Angular 7 Framework. The Angular 7 just released and it comes with a few new feature and improvements.

If you want to learn more about Angular, then check out this Angular 7 – The complete Guide course.

Angular 7 Features and Upgrades

Angular 7 got released this year in October with multiple new features such as CLI Prompts, Virtual Scroll, Drag and Drop, Angular Budgets and many more. From this release, Angular supports Node 10 and simultaneously maintains Node 8 support with TypeScript 3.1 and RxJS 6.3. A new extension from @angular/schematics called prompts has been introduced with the CLI that will now prompt developers when running common commands such as ng new my-app. Following are the list of the new Angular 7 features and upgrades.

  1. A new ng-compiler
  2. CLI prompts
  3. Angular DoBootstrap
  4. Application performance is increased
  5. ScrollingModule and DragDropModule
  6. Ivy Renderer
  7. TypeScript 3.1
  8. RxJS 6.3

Workflow of Angular 7 Tutorial

We will create two separate projects. One is for Angular, and one is for Node.js | Express | MongoDB. That means one for frontend and one for the backend. We will create a backend API, and frontend will consume that API. For this example, I am using the following tech stacks and their versions.

  1. Node v10.11.0
  2. NPM v6.4.1
  3. AngularCLI v7.0.2
  4. MongoDB shell version v3.6.3
  5. MongoDB version v3.6.3
  6. Mac OS Mojave

Angular 7 CRUD Example | MEAN Stack Tutorial

First, we will install Angular 7 using Angular CLI, and then we will continue to develop the frontend and backend.

#1: Install Angular 7 and other dependencies.

If you have an older @angular/cli version, then you can run the following command to install the latest versions.

npm uninstall -g @angular/cli
npm cache verify
npm install -g @angular/cli

If you are going through any issues, then please check out my this How To Update Angular CLI To Version 7It will help you to update your Angular CLI, and you will be able to create a brand new Angular seven project.

Okay, now if you type the following command, you can see that we have updated Angular CLI.

 

Angular 7 CRUD Example | MEAN Stack Tutorial

Now, you will be able to create a new Angular project using the following command.

ng new angular7crud
cd angular7crud

 

MEAN Stack CRUD Example

After going inside the project folder, open the project in Visual Studio Code using the following command. If you are not using it, then start using it. It is the best Editor for Javascript development.

code .

At the time of installation, we have enabled to routing for our application. It is new in Angular 7 because it will prompt us while installing angular boilerplate. You can check the file called app-routing.module.ts file inside src >> app directory.

Next, install the Bootstrap 4 CSS Framework using the following command.

npm install bootstrap --save

Now, add it inside the angular.json file.

"styles": [
   "src/styles.css",
   "./node_modules/bootstrap/dist/css/bootstrap.min.css"
 ],

So, now we can use the Bootstrap 4 classes in our project. 

Start the Angular development server using the following command.

Related Posts
1 of 22
ng serve -o

 

Angular 7 Tutorial

Project Description

We will create a project, where the user can enter their User Name, Business Name, and GST Number from the form and submit the form. If the values are incorrect, then it will validate at the frontend and form will not submit. If all the values seem perfect, then we will be able to send the form to backend API, and it will store the values inside the MongoDB database.

So now, we will create some angular components to do the job.

#2: Generate Angular Components

Type the following command to generate Angular 7 Components. We will perform create, read, update operations. So we will create three components.

ng g c gst-add --spec=false
ng g c gst-get --spec=false
ng g c gst-edit --spec=false

 

Angular CRUD Tutorial

All the three components are automatically registered inside an app.module.ts file. Now, we need to configure the routing of angular components inside an app-routing.module.ts file.

// app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GstAddComponent } from './gst-add/gst-add.component';
import { GstEditComponent } from './gst-edit/gst-edit.component';
import { GstGetComponent } from './gst-get/gst-get.component';

const routes: Routes = [
  {
    path: 'business/create',
    component: GstAddComponent
  },
  {
    path: 'business/edit/:id',
    component: GstEditComponent
  },
  {
    path: 'business',
    component: GstGetComponent
  }
];

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

export class AppRoutingModule { }

Now, you can see inside the app.component.html file that <router-outlet> directive is there. This directive helps us to render the different component based on the route URI.

#3: Create an Angular Navigation

Write the following code inside the app.component.html file.

<nav class="navbar navbar-expand-sm bg-light">
  <div class="container-fluid">
    <ul class="navbar-nav">
      <li class="nav-item">
        <a routerLink="business/create" class="nav-link" routerLinkActive="active">
          Create Business
        </a>
      </li>
      <li class="nav-item">
        <a routerLink="business" class="nav-link" routerLinkActive="active">
          Business
        </a>
      </li> 
    </ul>
  </div>
</nav>

<div class="container">
  <router-outlet></router-outlet>
</div>

Save the file and go to the browser and click on two links. You can see that we can see the different components based on the navigation.

#4: Install Angular Routing Progress Indicator.

Type the following command to install the ng2-slim-loading-bar library.

npm install ng2-slim-loading-bar --save

So, if you install third-party packages right now, then it is not compatible with Angular 7. To bridge the gap between Angular 7 and third-party packages, we need to install the following library. That is it.

npm install rxjs-compat --save

Now, import the SlimLoadingBarModule inside the app.module.ts file.

// app.module.ts

import { SlimLoadingBarModule } from 'ng2-slim-loading-bar';

imports: [
    ...
    SlimLoadingBarModule
],

Next step is, include the styling that comes with the library inside src  >>  styles.css file.

@import "../node_modules/ng2-slim-loading-bar/style.css";

#5: Adding Router Events.

Angular RouterModule gives us the following event modules.

  1. NavigationStart
  2. NavigationEnd
  3. NavigationError
  4. NavigationCancel
  5. Router
  6. Event

Now, write the following code inside the  app.component.ts file.

// app.component.ts

import { Component } from '@angular/core';
import {SlimLoadingBarService} from 'ng2-slim-loading-bar';
import { NavigationCancel,
        Event,
        NavigationEnd,
        NavigationError,
        NavigationStart,
        Router } from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular7crud';
  constructor(private _loadingBar: SlimLoadingBarService, private _router: Router) {
    this._router.events.subscribe((event: Event) => {
      this.navigationInterceptor(event);
    });
  }
  private navigationInterceptor(event: Event): void {
    if (event instanceof NavigationStart) {
      this._loadingBar.start();
    }
    if (event instanceof NavigationEnd) {
      this._loadingBar.complete();
    }
    if (event instanceof NavigationCancel) {
      this._loadingBar.stop();
    }
    if (event instanceof NavigationError) {
      this._loadingBar.stop();
    }
  }
}

What it is doing that it intercepts the routing event and add the loading bar component to every route so that we can see the routing indication every time we change the routes.

The final change to display routing indicator is that we need to add the ng2-slim-loading-bar directive inside the app.component.html file at the top of the page.

<ng2-slim-loading-bar color="blue"></ng2-slim-loading-bar>

<nav class="navbar navbar-expand-sm bg-light">
  <div class="container-fluid">
    <ul class="navbar-nav">
      <li class="nav-item">
        <a routerLink="business/create" class="nav-link" routerLinkActive="active">
          Create Business
        </a>
      </li>
      <li class="nav-item">
        <a routerLink="business" class="nav-link" routerLinkActive="active">
          Business
        </a>
      </li> 
    </ul>
  </div>
</nav>

<div class="container">
  <router-outlet></router-outlet>
</div>

Save the file and go to the terminal to see if there any error and if not then go to the browser and change the routes, and you can see that now we can see the routing indicator.

#6: Add Bootstrap Form

Inside the gst-add.component.html file, add the following bootstrap 4 form.

<div class="card">
  <div class="card-body">
    <form>
      <div class="form-group">
        <label class="col-md-4">Person Name</label>
        <input type="text" class="form-control" />
      </div>
      <div class="form-group">
        <label class="col-md-4">Business Name </label>
        <input type="text" class="form-control" />
      </div>
      <div class="form-group">
        <label class="col-md-4">Business GST Number </label>
        <input type="text" class="form-control" />
      </div>
      <div class="form-group">
        <button type="submit" class="btn btn-primary">Add Business</button>
      </div>
    </form>
  </div>
</div>

 

Angular 7 CRUD Demo

#7: Add Angular Form Validation

We will use ReactiveFormsModule. So if you are new to Angular Form Validation, then please check out my this article Angular 7 Form Validation Example Tutorial on this blog.

Now, import the ReactiveFormsModule inside the app.module.ts file.

// app.module.ts

import { ReactiveFormsModule } from '@angular/forms';

imports: [
    ...
    ReactiveFormsModule
],

Now, we need to write the code for the app.component.ts file. Remember, this is not template-driven form. So we will change the code inside the app.component.ts file.

First, we import the FormGroup, FormBuilder, Validators modules from @angular/forms.

Also, create a constructor and instantiate the FormBuilder.

So write the following code inside the gst-add.component.ts file.

// gst-add.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup,  FormBuilder,  Validators } from '@angular/forms';

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

  angForm: FormGroup;
  constructor(private fb: FormBuilder) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      person_name: ['', Validators.required ],
      business_name: ['', Validators.required ],
      business_gst_number: ['', Validators.required ]
    });
  }

  ngOnInit() {
  }

}

We have used form builder to handle all the validation. So in that constructor, we are creating a form with the validation rules. In our example, there are three fields. If input text is empty, then it will give an error, and we need to display that error.

Now, write the following code inside the gst-add.component.html file.

<div class="card">
  <div class="card-body">
    <form [formGroup]="angForm" novalidate>
      <div class="form-group">
        <label class="col-md-4">Person Name</label>
        <input type="text" class="form-control" formControlName="person_name" #person_name />
      </div>
      <div *ngIf="angForm.controls['person_name'].invalid && (angForm.controls['person_name'].dirty || angForm.controls['person_name'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['person_name'].errors.required">
          Person Name is required.
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Business Name </label>
        <input type="text" class="form-control" formControlName="business_name" #business_name />
      </div>
      <div *ngIf="angForm.controls['business_name'].invalid && (angForm.controls['business_name'].dirty || angForm.controls['business_name'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['business_name'].errors.required">
          Person Business is required.
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Business GST Number </label>
        <input type="text" class="form-control" formControlName="business_gst_number" #business_gst_number />
      </div>
      <div *ngIf="angForm.controls['business_gst_number'].invalid && (angForm.controls['business_gst_number'].dirty || angForm.controls['business_gst_number'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['business_gst_number'].errors.required">
          Business GST Number is required.
        </div>
      </div>
      <div class="form-group">
        <button type="submit" 
        [disabled]="angForm.pristine || angForm.invalid" 
        class="btn btn-primary">Add Business</button>
      </div>
    </form>
  </div>
</div>

Save the file and go to the browser and you can see, if you do not put any value inside the input box, then you will see the errors.

 

Angular 7 Form Validation Example

#8: Configure the HttpClientModule

Import the HttpClientModule inside the app.module.ts file.

// app.module.ts

import { HttpClientModule } from '@angular/common/http';

imports: [
   ...
    HttpClientModule
 ],

#9: Create a model.

Inside the src >> app folder, create one file called Business.ts and add the following code.

// Business.ts

export default class Business {
  person_name: String;
  business_name: String;
  business_gst_number: Number;
}

#10: Create an Angular Service file.

Type the following command to generate the service file.

ng g service business --spec=false

So, your primary business.service.ts file looks like this.

// business.service.ts

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

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

  constructor() { }
}

Now, import the business.service.ts file into the app.module.ts file.

// app.module.ts

import { BusinessService } from './business.service';

providers: [ BusinessService ],

#11: Submit the data to the node server

Now, we need to write the code that will send the HTTP POST request with the data to the Node.js server and save the data into the MongoDB database.

Write the following code inside the business.service.ts file.

// business.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

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

  uri = 'http://localhost:4000/business';

  constructor(private http: HttpClient) { }

  addBusiness(person_name, business_name, business_gst_number) {
    const obj = {
      person_name: person_name,
      business_name: business_name,
      business_gst_number: business_gst_number
    };
    console.log(obj);
    this.http.post(`${this.uri}/add`, obj)
        .subscribe(res => console.log('Done'));
  }
}

We have defined our backend API URL, but we have not created any backend yet, but we will do in a couple of steps.

Now, we need to add the click event to the Add Business Button. So add the following code inside the gst-add.component.html file.

<div class="form-group">
    <button (click)="addBusiness(person_name.value, business_name.value, business_gst_number.value)"
        [disabled]="angForm.pristine || angForm.invalid" 
        class="btn btn-primary">
        Add Business
     </button>
</div>

So when there are no errors, we can submit the form, and it will call the component’s addBusiness function. From there, we will call the angular service and service will send the HTTP Post request to the Node.js server.

Now, add the addBusiness function inside the gst-add.component.ts file. So write the following code inside the gst-add.component.ts file.

// gst-add.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup,  FormBuilder,  Validators } from '@angular/forms';
import { BusinessService } from '../business.service';

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

  angForm: FormGroup;
  constructor(private fb: FormBuilder, private bs: BusinessService) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      person_name: ['', Validators.required ],
      business_name: ['', Validators.required ],
      business_gst_number: ['', Validators.required ]
    });
  }

  addBusiness(person_name, busines_name, business_gst_number) {
    this.bs.addBusiness(person_name, busines_name, business_gst_number);
  }

  ngOnInit() {
  }

}

Here, we have defined the function and also imported the business.service.ts file. Instantiate the object inside the constructor and use that to call the function of the businsess.service.ts file.

We have already coded the addBusiness function inside the business.service.ts file. Now, we need to configure the backend API.

#12: Create a Node.js backend API

Inside the angular root folder, create one folder called api and go inside that folder. Remember, it will be a completely separate project from Angular. So its node_modules are different from an Angular.

Open the terminal inside the api folder and type the following command.

npm init -y

Install the following node specific modules.

npm install --save express body-parser cors mongoose

I do not restart node server each time; I change the file. So I am installing the nodemon server. What it does is that, when I modify the server.js file, it restarts the node.js server automatically.

npm install nodemon --save-dev

Now, inside the api folder, create one file called the server.js file.

// server.js

const express = require('express'),
    path = require('path'),
    bodyParser = require('body-parser'),
    cors = require('cors'),
    mongoose = require('mongoose');

    const app = express();
    let port = process.env.PORT || 4000;

    const server = app.listen(function(){
        console.log('Listening on port ' + port);
    });

The next thing is to connect MongoDB database with our node.js application.

If you have not installed the MongoDB database then install it and then start the mongodb server.

Type the following command to start the MongoDB server.

mongod

So, Now, I have connected to the database.

Create one file called DB.js inside api root project folder. Write the following code inside the DB.js file.

// DB.js

module.exports = {
    DB: 'mongodb://localhost:27017/ng7crud'
 };

Import this DB.js file inside our server.js file and use mongoose library to set up the database connection with MongoDB. We can also use Mongoose to save the data in the database using Mongoose ORM.

Write the following code inside the server.js file to connect our MongoDB application to the Node.js server.

// server.js

const express = require('express'),
    path = require('path'),
    bodyParser = require('body-parser'),
    cors = require('cors'),
    mongoose = require('mongoose'),
    config = require('./DB');

    mongoose.Promise = global.Promise;
    mongoose.connect(config.DB, { useNewUrlParser: true }).then(
      () => {console.log('Database is connected') },
      err => { console.log('Can not connect to the database'+ err)}
    );

    const app = express();
    app.use(bodyParser.json());
    app.use(cors());
    const port = process.env.PORT || 4000;

    const server = app.listen(port, function(){
     console.log('Listening on port ' + port);
    });

Save the file and go to the terminal and start the node server.

nodemon server

So, right now, you have three servers are running.

  1. Angular Development Server
  2. Nodemon server
  3. MongoDB server

Remember all the three servers are running fine without any error otherwise, our application will not work.

#13: Create model and routes for our application.

Now, we need to create two folders inside the api root folder called routes and models.

In models folder, create one model called Business.js.

// Business.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Define collection and schema for Business
let Business = new Schema({
  person_name: {
    type: String
  },
  business_name: {
    type: String
  },
  business_gst_number: {
    type: Number
  }
},{
    collection: 'business'
});

module.exports = mongoose.model('Business', Business);

So, we have defined our schema for the business collection. We have three fields called person_name, business_name, business_gst_number.

In the routes folder, create one file called the business.route.js.

Write the CRUD code inside the business.route.js file.

// business.route.js

const express = require('express');
const app = express();
const businessRoutes = express.Router();

// Require Business model in our routes module
let Business = require('../models/Business');

// Defined store route
businessRoutes.route('/add').post(function (req, res) {
  let business = new Business(req.body);
  business.save()
    .then(business => {
      res.status(200).json({'business': 'business in added successfully'});
    })
    .catch(err => {
    res.status(400).send("unable to save to database");
    });
});

// Defined get data(index or listing) route
businessRoutes.route('/').get(function (req, res) {
    Business.find(function (err, businesses){
    if(err){
      console.log(err);
    }
    else {
      res.json(businesses);
    }
  });
});

// Defined edit route
businessRoutes.route('/edit/:id').get(function (req, res) {
  let id = req.params.id;
  Business.findById(id, function (err, business){
      res.json(business);
  });
});

//  Defined update route
businessRoutes.route('/update/:id').post(function (req, res) {
    Business.findById(req.params.id, function(err, next, business) {
    if (!business)
      return next(new Error('Could not load Document'));
    else {
        business.person_name = req.body.person_name;
        business.business_name = req.body.business_name;
        business.business_gst_number = req.body.business_gst_number;

        business.save().then(business => {
          res.json('Update complete');
      })
      .catch(err => {
            res.status(400).send("unable to update the database");
      });
    }
  });
});

// Defined delete | remove | destroy route
businessRoutes.route('/delete/:id').get(function (req, res) {
    Business.findByIdAndRemove({_id: req.params.id}, function(err, business){
        if(err) res.json(err);
        else res.json('Successfully removed');
    });
});

module.exports = businessRoutes;

Here, we have used the mongoose model to save, update, delete the data from the database. Mongoose is an ORM used in MongoDB database. Now, we have all the CRUD operations set up on the route file; we need to import inside the server.js file.

So, our final server.js file looks like this.

// server.js

const express = require('express'),
    path = require('path'),
    bodyParser = require('body-parser'),
    cors = require('cors'),
    mongoose = require('mongoose'),
    config = require('./DB');

const businessRoute = require('./routes/business.route');
mongoose.Promise = global.Promise;
mongoose.connect(config.DB, { useNewUrlParser: true }).then(
  () => {console.log('Database is connected') },
  err => { console.log('Can not connect to the database'+ err)}
);

const app = express();
app.use(bodyParser.json());
app.use(cors());
app.use('/business', businessRoute);
const port = process.env.PORT || 4000;

const server = app.listen(port, function(){
  console.log('Listening on port ' + port);
});

#14: Test the store data functionality

If your all the servers are up and running then you can go to the browser and fill the form data and add the business. You can see something like this on your screen if you are successful.

 

MEAN Stack Tutorial

Now, we can check on the database using the following commands.

First, open the mongo shell on the 4th tab because all the other three tabs are occupied at the moment.

mongo

 

MongoDB CRUD

Here, we can see that the values are storing in the MongoDB database. Yess!! We have succeeded.

Now, remaining operations are Read, Update, and Delete.

#15: Display the data on frontend

In the gst-get.component.html file, write the following code.

<table class="table table-hover">
  <thead>
  <tr>
      <td>Person Name</td>
      <td>Business Name</td>
      <td>GST Number</td>
      <td colspan="2">Actions</td>
  </tr>
  </thead>

  <tbody>
      <tr *ngFor="let business of businesses">
          <td>{{ business.person_name }}</td>
          <td>{{ business.business_name }}</td>
          <td>{{ business.business_gst_number }}</td>
          <td><a [routerLink]="['/edit', business._id]" class="btn btn-primary">Edit</a></td>
          <td><a [routerLink]="" class="btn btn-danger">Delete</a></td>
      </tr>
  </tbody>
</table>

Now, inside the business.service.ts file, we need to write the function that fetches the businesses data from the MongoDB database and display at the Angular application.

// business.service.ts

getBusinesses() {
    return this
           .http
           .get(`${this.uri}`);
  }

Now, we need to include this business.service.ts file and Business.ts file inside the gst-get.component.ts file.

Write the following code inside the gst-get.component.ts file.

// gst-get.component.ts

import { Component, OnInit } from '@angular/core';
import Business from '../Business';
import { BusinessService } from '../business.service';

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

  businesses: Business[];

  constructor(private bs: BusinessService) { }

  ngOnInit() {
    this.bs
      .getBusinesses()
      .subscribe((data: Business[]) => {
        this.businesses = data;
    });
  }
}

Save the file and go to the browser and switch to this URL: http://localhost:4200/business. You can see the listing of the businesses.

#16: Edit and Update Data

Okay, first, we need to fetch the data from the MongoDB database using _id wise and display that data in the gst-edit.component.html file.

So first, write the following code inside the gst-edit.component.ts file.

// gst-edit.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { FormGroup,  FormBuilder,  Validators } from '@angular/forms';
import { BusinessService } from '../business.service';

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

  business: any = {};
  angForm: FormGroup;

  constructor(private route: ActivatedRoute,
    private router: Router,
    private bs: BusinessService,
    private fb: FormBuilder) {
      this.createForm();
 }

  createForm() {
    this.angForm = this.fb.group({
        person_name: ['', Validators.required ],
        business_name: ['', Validators.required ],
        business_gst_number: ['', Validators.required ]
      });
    }


  ngOnInit() {
    this.route.params.subscribe(params => {
        this.bs.editBusiness(params['id']).subscribe(res => {
          this.business = res;
      });
    });
  }
}

Here, when the gst-edit component.ts render, it will call the ngOnInit method and send an HTTP request to the node server and fetch the data from a _id to display inside the gst-edit.component.html file.

Now, inside the business.service.ts file, we need to code the editBusiness function to send an HTTP request.

// business.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

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

  uri = 'http://localhost:4000/business';

  constructor(private http: HttpClient) { }

  addBusiness(person_name, business_name, business_gst_number) {
    const obj = {
      person_name: person_name,
      business_name: business_name,
      business_gst_number: business_gst_number
    };
    this.http.post(`${this.uri}/add`, obj)
        .subscribe(res => console.log('Done'));
  }

  getBusinesses() {
    return this
           .http
           .get(`${this.uri}`);
  }

  editBusiness(id) {
    return this
            .http
            .get(`${this.uri}/edit/${id}`);
    }
}

Now, finally, we need to write the form inside the gst-edit.component.html file.

<div class="card">
  <div class="card-body">
    <form [formGroup]="angForm" novalidate>
      <div class="form-group">
        <label class="col-md-4">Person Name</label>
        <input type="text" class="form-control" formControlName="person_name" #person_name [(ngModel)] = "business.person_name" />
      </div>
      <div *ngIf="angForm.controls['person_name'].invalid && (angForm.controls['person_name'].dirty || angForm.controls['person_name'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['person_name'].errors.required">
          Person Name is required.
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Business Name </label>
        <input type="text" class="form-control" formControlName="business_name" #business_name [(ngModel)] = "business.business_name" />
      </div>
      <div *ngIf="angForm.controls['business_name'].invalid && (angForm.controls['business_name'].dirty || angForm.controls['business_name'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['business_name'].errors.required">
          Person Business is required.
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Business GST Number </label>
        <input type="text" class="form-control" formControlName="business_gst_number" #business_gst_number [(ngModel)] = "business.business_gst_number" />
      </div>
      <div *ngIf="angForm.controls['business_gst_number'].invalid && (angForm.controls['business_gst_number'].dirty || angForm.controls['business_gst_number'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['business_gst_number'].errors.required">
          Business GST Number is required.
        </div>
      </div>
      <div class="form-group">
        <button (click)="updateBusiness(person_name.value, business_name.value, business_gst_number.value)"
        [disabled]="angForm.invalid" 
        class="btn btn-primary">Update Business</button>
      </div>
    </form>
  </div>
</div>

Save the file and go to the listing page and click on the edit button and you will see the populated form from the database.

You can also see the warning like the following. Ignore for this demo tutorial.

forms.js:1193
It looks like you’re using ngModel on the same form field as formControlName.
Support for using the ngModel input property and ngModelChange event with
reactive form directives have been deprecated in Angular v6 and will be removed
in Angular v7.
Now, update the data. Inside the business.service.ts file, we need to write the function that updates the data.
// business.service.ts

updateBusiness(person_name, business_name, business_gst_number, id) {

    const obj = {
        person_name: person_name,
        business_name: business_name,
        business_gst_number: business_gst_number
      };
    this
      .http
      .post(`${this.uri}/update/${id}`, obj)
      .subscribe(res => console.log('Done'));
  }

Okay, now write the updateBusiness() function inside gst-edit.component.ts file.

// gst-edit.component.ts

updateBusiness(person_name, business_name, business_gst_number) {
   this.route.params.subscribe(params => {
      this.bs.updateBusiness(person_name, business_name, business_gst_number, params['id']);
      this.router.navigate(['business']);
});

Save the file, and you will be able to update the data.

#17: Delete the data.

So, if you find no error on the console, then you can successfully update the data.

 I have already written edit and update service to make an API calls. So till now, Create, Read, Update is complete of this Angular 7 CRUD Example Tutorial. Now, take a look at Delete.

Now, we need to define click event on the delete button inside the gst-get.component.html file.

<tr *ngFor="let business of businesses">
          <td>{{ business.person_name }}</td>
          <td>{{ business.business_name }}</td>
          <td>{{ business.business_gst_number }}</td>
          <td><a [routerLink]="['edit', business._id]" class="btn btn-primary">Edit</a></td>
          <td><a (click) = "deleteBusiness(business._id)" class="btn btn-danger">Delete</a></td>
</tr>

Now, write the deleteBusiness function inside the gst-get.component.ts file.

// gst-get.component.ts

deleteBusiness(id) {
    this.bs.deleteBusiness(id).subscribe(res => {
      console.log('Deleted');
    });
  }

Finally, create deleteBusiness() function inside the business.service.ts file.

// business.service.ts

deleteBusiness(id) {
    return this
              .http
              .get(`${this.uri}/delete/${id}`);
  }

Finally, Completed the delete functionality.

So, in this tutorial, we have complete the CRUD Functionality in Angular 7.

If you have any doubt in this Angular 7 CRUD Example, then ask in a comment below.

Github Code

53 Comments
  1. Dobby says

    Why didn’t you use angular material instead of bootstrap? It would be very nice article for me. Anyway, thanks for this article tho.

  2. Poly says

    Why didn’t you use Angular Material instead of bootstrap? it would be very nice. Thanks anyway.

  3. Doly says

    Why didn’t you use Angular Material instead of bootstrap? it would be very nice. Thank you!

    1. Krunal says

      Will use for future projects.

  4. lamasbr says

    Firstly, I would like to thank you for this article. I am learning Angular for the first time now and your article was very helpful.

    I had a problem with the edit form. When I click on Edit button, change any field and submit, the following error was displayed in the console: “Form submission canceled because the form is not connected”. To workaround this, was necessary add type=”button” on the submit button.

    Now I have another issue, when I submit the edit form with new values, I’m redirected to the initial page but to see the new values, I need to refresh manually. How can I fix it?

    Thank you,
    Cheers from Brazil.

  5. þorN says

    Thanks a lot, it works for me. I had to change the link in the list to the edit component from /edit to /business/edit

  6. Aravind says

    I’m getting this error ,
    Can’t able to find where i went wrong
    `this.bs.addBusiness is not a function
    at GstAddComponent.push../src/app/gst-add/gst-add.component.ts.GstAddComponent.addBusiness (gst-add.component.ts:30)`

    1. Krunal says

      You need to add the addBusiness function. You can refer my GitHub code.

  7. Cody says

    I really like this tutorial except for one little thing. Why didn’t you write the back-end API in Typescript? You did the front end in Typescript.

  8. sundar says

    project is working. Add Business button is clicking value added in mongodb. but page cannot be refreshed. same problem for delete and view. how can set for page reload in value added.

  9. Bert Wilms says

    Hi, i’m new in Angular, Nodejs development. I would like to thank you for this Article.
    unfortunately, i’m not able to figure out why i get following error.
    POST http://localhost:4000/business/add 404 (Not Found)
    core.js:12501 ERROR HttpErrorResponse {headers: HttpHeaders, status: 404, statusText: “Not Found”, url: “http://localhost:4000/business/add”, ok: false, …}error: “↵↵↵↵Error↵↵↵Cannot POST /business/add↵↵↵”headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}message: “Http failure response for http://localhost:4000/business/add: 404 Not Found”name: “HttpErrorResponse”ok: falsestatus: 404statusText: “Not Found”url: “http://localhost:4000/business/add”__proto__: HttpResponseBase

    When i start the nodeserver everything looks fine.
    [nodemon] starting `node server.js`
    Listening on port 4000
    Database is connected

    The mongodb is up and running. i’ve tried local, and also with a db on cloud.mongodb.com atlas.

    Could you help me please,
    Thx,
    Bert

    1. Juls says

      Same problem here tried to restart nodemon but now i cannot run error 48 on my ubuntu.. Have you tried to edit the service change to uri = ‘/business ‘ only? Thanks

    2. Juls says

      I encountered the same problem and i solved now by adding permission on mongodb. My problem now is unable to submit after the edit and cant delete item.. Anyone can help? I check my node it stop after delete or edit and need to restart..

      1. Mohan says

        I did not face issue with delete, but yes with edit.
        Changed business.route.js where “Business.findById(req.params.id, function(err, next, business)” the retrieved data was present in NEXT and ended up using that object instead of the BUSINESS for the update.

    3. Mohammed Safee Uddin says

      Remove process.ENV || from the port variable in server.js and send the port as a parameter in app.listen() function of server variable. Don’t forget to change keep the same port number at your client business.service.ts in uri variable and port variable in server.js

    4. ifthikar says

      POST http://localhost:4000/business/add 404 (Not Found)
      core.js:12501 ERROR HttpErrorResponse {headers: HttpHeaders, status: 404, statusText: “Not Found”, url: “http://localhost:4000/business/add”, ok: false, …}error: “↵↵↵↵Error↵↵↵Cannot POST /business/add↵↵↵”headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}message: “Http failure response for http://localhost:4000/business/add: 404 Not Found”name: “HttpErrorResponse”ok: falsestatus: 404statusText: “Not Found”url: “http://localhost:4000/business/add”__proto__: HttpResponseBase HOW DID YOU FIX THIS PROBLEM?

    5. Arnold says

      In business.service.ts file the uri variable change it to ‘/business’. In Server.js change port to 4200 and remove process.ENV ||.

  10. Juls says

    Same problem here tried to restart nodemon but now i cannot run error 48 on my ubuntu.. Have you tried to edit the service change to uri = ‘/business ‘ only? Thanks

  11. Paul says

    Hi! Good tutorial.
    i’m a beginner in angular and I meet a problem when i run nodemon server, can you help me to understand this error!
    That’s my error code:

    [nodemon] 1.18.7
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching: *.*
    [nodemon] starting `node server index.js`
    internal/modules/cjs/loader.js:582
    throw err;
    ^

    Error: Cannot find module ‘/home/odon/Bureau/angular7CRUD/index.js’
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:580:15)
    at Function.Module._load (internal/modules/cjs/loader.js:506:25)
    at Function.Module.runMain (internal/modules/cjs/loader.js:741:12)
    at startup (internal/bootstrap/node.js:285:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:739:3)
    [nodemon] app crashed – waiting for file changes before starting…

    1. Nandini Verma says

      run the nodemon server in /api directory

  12. Apurva says

    Hi,
    This is a nice tutorial so far, but I’m getting an error while edit

    enableProdMode() to enable the production mode.
    core.js:14597 ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: ‘edit/5c0504f2c89130599b6199f7’
    Error: Cannot match any routes. URL Segment: ‘edit/5c0504f2c89130599b6199f7’
    at ApplyRedirects.push../node_modules/@angular/router/fesm5/router.js.ApplyRedirects.noMatchError (router.js:2469)
    at CatchSubscriber.selector (router.js:2450)
    at CatchSubscriber.push../node_modules/rxjs/_esm5/internal/operators/catchError.js.CatchSubscriber.error (catchError.js:34)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._error (Subscriber.js:80)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.error (Subscriber.js:60)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._error (Subscriber.js:80)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.error (Subscriber.js:60)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._error (Subscriber.js:80)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.error (Subscriber.js:60)
    at

    1. Hoang says

      You need to change the routerlink in gst-get.component.html file to:Edit

  13. Nics says

    Update function not working.

  14. narmit says

    Hey can you do this with ms sql instead of mongodb. I tried to do it but i cant get it to work

  15. Mosu says

    Thank you for your tutorial.

    By the way, is there any way to get a page refresh a data after edit page?
    I try to get it work even with a navigate to homepage then back to business page but it doesn’t work

  16. Himanshu Chhatbar says

    Nice article

  17. Mihajlo says

    Hey, tnx for the article, nice work.

  18. khaledmoez says

    hello,
    thank you for your tutoriel, it was very helpful.
    I think there is a little mistake in the text you wrote at the begining of paragraph #13.
    you say :
    “Now, we need to create two folders inside the root folder called routes and models.”

    i think you should add the word “api” so the sentence would become:
    “Now, we need to create two folders inside the api root folder called routes and models.”

    Regards

  19. Pankaja says

    Hi kunal,
    I am issue when we migrated our Angular 4 application served up via nodejs to Angular 7. All the migration went smooth and was able to make the necessary coding changes. But I keep getting the following error – “ERROR in ./node_modules/jsonpath/generated/parser.js
    Module not found: Error: Can’t resolve ‘fs’… ” along with similar error for ‘path’ … So then I realized that while building the app it is trying to compile the server.js file as well and that is where both the require(‘fs’) and require(‘path’) are in the code. I am not sure what in addition we have to do here in Angular 7 so this error doesn’t occur. Any help is greatly appreciated.
    Thanks

  20. Monaj says

    Hi

    Thanks for the tutorial. I had a few errors with delete function, and mongose functions, and had to copy paste your code from github to make it work.

    Please, what is the easiest way to make the initial homepage UPDATE whenever there is an update or deletion ?

    Also, what’s the easiest and most efficient sanitizing methods that would be of use here server side I mean to avoid mysql injection

  21. dhamodar says

    // plz add port variable in app.listen like this so node server is available
    const server = app.listen(port,function(){
    console.log(‘Listening on port ‘ + port);
    });

  22. Manidip Mandal says

    Every is working fine but data in updating in real time. i am pretty new in this. Suppose i have edited a business and cam back t business list but nothing reflected until i refresh the page. Please help..

  23. Waleed Umer says

    Very nice article.

    Now how to publish this whole project?

    By simply using “ng build –prod” command ?

  24. Luke Harris says

    to have the page update automatically after an edit, change the business service “updateBusiness()” so it no longer subscribes response, and return the response instead:

    updateBusiness(person_name, business_name, business_gst_number,id){
    const obj = {
    person_name: person_name,
    business_name: business_name,
    business_gst_number: business_gst_number
    };
    return this.http.post(`${this.uri}/update/${id}`, obj);
    }

    Then, in your gst-edit.component, subscribe to the response so you know when the async call is finished, then navigate back to the business page:

    updateBusiness(person_name, business_name, business_gst_number){
    this.route.params.subscribe(params => {
    this.bs.updateBusiness(person_name, business_name, business_gst_number, params[‘id’]).subscribe((data: string) =>{
    console.log(data);
    this.router.navigate([‘business’]);
    });
    })
    }

    To auto-update on a delete, create a function that pulls the records just like ngOnInit() does:

    getBusinesses(): void {
    this.bs
    .getBusinesses()
    .subscribe((data: Business[]) => {
    this.businesses = data;
    })
    }

    Change the deleteBusiness() function as follows:

    deleteBusiness(id) {
    this.bs.deleteBusiness(id).subscribe(res => {
    console.log(‘Deleted’);
    this.getBusinesses();
    });
    }

    You can now also replace the function in ngOnInit() with your new function:

    ngOnInit() {
    this.getBusinesses();
    }

    1. russunit says

      Thanks Luke;

      to piggyback on this idea, I added code to navigate to the business list page and update on adding a business.

      in business.service.ts:

      addBusiness(person_name, business_name, business_gst_number) {
      const obj = {
      person_name: person_name,
      business_name: business_name,
      business_gst_number: business_gst_number
      };
      console.log(obj);
      return this.http.post(`${this.uri}/add`, obj);
      }

      In gst-add.component.ts:

      addBusiness(person_name, business_name, business_gst_number) {
      this.route.params.subscribe(params => {
      this.bs.addBusiness(person_name, business_name, business_gst_number).subscribe((data:string) =>{
      console.log(data);
      this.router.navigate([‘business’]);
      });
      })
      }

  25. Jeffrey says

    This is great. I found this really useful.
    I’d like to know how I can containerize this entire project using docker.

  26. N1cK says

    Great tutorial ! One little mistake though: It needs to be

    Add Business

  27. azhar khan says

    its very good and easy to understand

    i am from india

  28. Kelvin Nganga says

    For some reason my update doesn’t work…i made some few changes to be able to view the edit page..once i edit the information and try to update…it throws an error..as well as crushes my back end..wondering there was an issue in routing ..or we sending data the wrong way…anyone who has encountered similar issue and figured it out would appreciate any ideas..

    errors

    throw er; // Unhandled ‘error’ event..this pops up on my console..together with app crashed waiting for file changes before starting..

    when i inspect my page on the browser…i get bellow error
    Failed to load :4000/business/update/5c58867ae9b49122530bbfb8:1 F
    resource: net::ERR_CONNECTION_REFUSED

    1. Tanvi Desai says

      I could solve this error by removing next in update in business.route.js
      // Defined update route
      businessRoutes.route(‘/update/:id’).post(function (req, res) {

      and also implemented changes suggested by Luke Harris for auto-refresh after successful update.

  29. Guillermo says

    Thank You!

  30. Harsha says

    Thanks a lot Krunal.

    After searching, and following loads of video tutorials, I have found what I was looking … A Simple Mean Stack Tutorial that works. I wanted to know how the back end and the front end connects. Its all there!!!

  31. russunit says

    “If you have not installed the MongoDB database then install it…”

    could someone please give instructions to install the MongoDB database? I have installed the node package for MongoDB but I don’t see where there are instructions to install the database.

    1. russunit says

      edit: I am getting a 400 error when I try to add a business so I believe my problem is missing this step… I get the same error both on the code I built from the tutorial and on the code that i cloned from github.

      1. russunit says

        edit: Nevermind, my 400 error was from trying to use letters for the business number field.

      2. russunit says

        edit: my issue was that I was trying to enter a non-numeric entry for the GST Number.

        To validate this field to be sure it’s a number, in gst-add.component.ts, replace this line:
        business_gst_number: [”, Validators.required ]

        with this line:
        business_gst_number: [”, Validators.compose([
        Validators.required,
        Validators.pattern(‘[0-9]+’)
        ]) ]

        Then, in gst-add.component.ts, add this block under the “business gst number is required” div:

        Business GST Number must be an integer.

  32. russunit says

    I was getting a 400 error trying to enter a non-numeric entry for the GST Number.

    To validate this field to be sure it’s a number, in gst-add.component.ts, replace this line:
    business_gst_number: [”, Validators.required ]

    with this line:
    business_gst_number: [”, Validators.compose([
    Validators.required,
    Validators.pattern(‘[0-9]+’)
    ]) ]

    Then, in gst-add.component.ts, add this block under the “business gst number is required” div:

    Business GST Number must be an integer.

  33. Lovely says

    Edit Function is not working. It show error :
    ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: ‘edit/5c80a7850c013406ecac4c74’
    Error: Cannot match any routes. URL Segment: ‘edit/5c80a7850c013406ecac4c74’
    Please help me to solve this.

    1. Lala Von Puddles says

      Hi Lovely,

      In gst-get.component.html change this router link from this:
      [routerLink]=”[‘/edit’, business._id]”

      To this:
      [routerLink]=”[‘/business/edit’, business._id]”

      Also, in your business.route.js update route function remove the ‘next’ param.
      Change from this:

      Business.findById(req.params.id, function(err, next, business)

      To this:
      Business.findById(req.params.id, function(err, business)

  34. Karan says

    Step #3 doesn’t seem to work with Angular 7.2.8. Nothing shows up in the browser.

  35. Gurmeet Singh says

    I have tried each and every step but add, display data didn’t work, there is no error while compiling, please help.

  36. mohd adnan shoheb says

    it was really helpful, don’t stop creating such project it helps a lot for freshers

  37. Aleksandr Skobeltcyn says

    Thanks, really useful boilerplate or starter kit

Leave A Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.