MEAN Stack CRUD Operations Using Angular Material Datatable

MEAN Stack CRUD Operations Using Angular Material Datatable

03 Aug 2022
Advanced
37.4K Views
30 min read
Learn with an interactive course and practical hands-on labs

Self-Paced Angular Certification Course

In this tutorial, you will learn how to create a MEAN Stack CRUD application from absolute scratch and we will share how to create an Angular CRUD application. To build the Angular MEAN CRUD app, we will use Angular Material, Node.js, Express.js, MongoDB, and Angular web applications.

For the demo purpose, we will learn the CRUD operations by creating an employee management system using the Angular MEAN stack and I will try to cover the essential configuration and features used in CRUD web application development.

In this part of the article, we are going to learn the CRUD operations step-by-step process to build an Angular app using the MEAN stack with the Angular Material Data table component from the scratch. Let's understand the MEAN Stack.

MEAN Stands for:

M - MongoDB

MongoDB is a NoSQL database, and it is an open-source database that is designed to provide faster performance than a relational database.

E - ExpressJs

express is a Web application framework that is built on top of the Nodejs, which provides many robust features for web and mobile applications.

A – Angular

Angular is an open-source front-end web application framework that is used to create single-page applications.

N – Nodejs

Nodejs is a JavaScript runtime that is built on Google’s V8 engine which is used to create a scalable network application.

MEAN Stack has many advantages because it has a collection of different JavaScript technologies to create robust, faster, and highly scalable web and mobile compatible applications very easily, In short, to develop MEAN Stack app we just need to understand only one language which is called JavaScript than we can build MEAN Stack app in an easy manner. So in this article, we are going to cover CRUD operation step by step with Angular Material Datatable with ease.

Project Structure

In our application, basically, we should have an angular project as front-end and for the backend, we need to implement some server-side code which is covered by nodejs and expressjs, below you can find the example of a mean stack app, but keep in mind that it can vary from person to person. Thus you can enhance the project structure as per your requirement to simplify such things.

There is no specific guideline regarding the project structure for the Angular application because the business need can be different for the different projects, hence choosing the best suitable project structure based on the weight of the requirement is more important.

Front-end Project

For the front-end, we are using the Angular application which contains a structure as given in the below snapshot. Primarily we are going to use three primary components to work with CRUD operations, at the end main advantage is to achieve the re-usability of the component by creating an independent component as given below.

  1. add-employee: To add new employees by adding details into the form
  2. edit-employee: To edit an employee's details by clicking on the edit button from the list of the employee's table
  3. list-employee: To list out all the set of employees from the database

Server Side

And for the server-side application, we are going to use the server configuration, routes, models, etc. So for that, I have basically created the three different folders Model, Routes, and Server respectively inside the separate server application /server and not into the Agular application structure.

So this is how the structure looks like if you want to cover every server-side file then you can create a separate folder for the server and put those files inside as well.

Prerequisites

To work with MEAN Stack, we need to have a few tools and packages to be installed into our respective applications of front-end and back-end.

Install Nodejs

https://nodejs.org/en/download/

Install MongoDB

https://www.mongodb.com/download-center

Code Editor

In this article, Visual studio code is used as the primary editor but you can use any other editor like sublime, visual studio, etc.

In this article, I am using a Windows operating system, but if you are using any other o/s then download and configure the above tools according to the download guidelines for the specific O/S.

Setup and Installation

After installing the above-listed tools and packages, now it’s time to install a few dependencies which we are being used throughout this article for both the front-end and back-end. For that, we need to execute a series of npm commands as listed below.

For server-side

npm command
Usage
npm install express
Acts as a back-end website framework
npm install mongoose
Acts as a Database for MEAN Stack application
npm install body-parser
Convert data into JSON format coming from API result
npm install cors
Acts as middleware and allow cors for an API request
npm install nodemon
To reload the node files automatically without stopping and starting the server again

For Client-Side

Here in this article, we are using the Angular Material Datatable component to list the set of employees, so for that, we are using the Angular Material Component and need to install the following dependencies before using it.

Npm command
Usage
Npm install @angular/material
To use all the angular material components in our angular application
Npm install @angular/cdk
It provides pre-defined behavior for your components

So far we have set up our application and with other essential dependencies which we are using in this MEAN Stack app, after the completion, the next step is to implement the CRUD operation step by step where we will first configure the back-end app and then Angular app respectively.

Setup of Backend

To get the CRUD operation with real-time data, we need to configure our backend using nodejs, expressjs, and MongoDB.

Setting Up Server Environment

Our first step is to create a server and provide the necessary configuration to the application such as database connectivity, importing the third-party packages, parsing the API request, for that just create a new folder named \server and inside the folder create a new file called server.js and paste the following code snippets.

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

// MongoDB Databse url
var mongoDatabase = 'mongodb://localhost:27017/employeeDetails';

// Created express server
const app = express();
mongoose.Promise = global.Promise;

// Connect Mongodb Database
mongoose.connect(mongoDatabase, { useNewUrlParser: true }).then(
 () => { console.log('Database is connected') },
 err => { console.log('There is problem while connecting database ' + err) }
);

// All the express routes
const employeeRoutes = require('../Routes/Employee.route');

// Conver incoming data to JSON format
app.use(bodyParser.json());

// Enabled CORS
app.use(cors());

// Setup for the server port number
const port = process.env.PORT || 4000;

// Routes Configuration
app.use('/employees', employeeRoutes);

// Staring our express server
const server = app.listen(port, function () {
 console.log('Server Lisening On Port : ' + port);
});

As you can see in the above server file, we have included multiple npm packages, express server configuration, route configuration, data formatted, etc. In the above file, I have already included the MongoDB database configuration which looks like this.

// MongoDB Databse url
var mongoDatabase = 'mongodb://localhost:27017/employeeDetails';

// Connect Mongodb Database
mongoose.connect(mongoDatabase, { useNewUrlParser: true }).then(
 () => { console.log('Database is connected') },
 err => { console.log('There is problem while connecting database ' + err) }
);

Here in this code snippet, I have added the database URL and at the end, we are going to connect the MongoDB database by using connect() method to ensure that the database is connected with our express application.

MongoDB Model Schema

In this article, we are going to use the schema of Employee management, which will allow us to create a CRUD operation user document. For that, I would suggest you create a new folder named \Model and inside the folder create a new file named Employee.js and paste the following code snippets.

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

// List of columns for Employee schema
let Employee = new Schema({
 firstName: {
 type: String
 },
 lastName: {
 type: String
 },
 email: {
 type: String
 },
 phone: {
 type: Number
 }
},{
 collection: 'employees'
});

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

So we have created a MongoDB collection schema in which I have added four different columns with the appropriate data types with the collection employees.

Crete API Controller or Routes

As we know that we are working with nodejs and express that we need to have routes to perform CRUD operations. To work with MongoDB user documents, we need to have an API controller which allows us to implement and use different routes for CRUD operations.

Create a folder named \Routes and inside the folder create a new file named Employee.route.js and paste the following code snippets.

// Importing important packages
const express = require('express');

// Using express and routes
const app = express();
const employeeRoute = express.Router();

// Employee module which is required and imported
let employeeModel = require('../Model/Employee');

// To Get List Of Employees
employeeRoute.route('/').get(function (req, res) {
 employeeModel.find(function (err, employee) {
 if (err) {
 console.log(err);
 }
 else {
 res.json(employee);
 }
 });
});

// To Add New Employee
employeeRoute.route('/addEmployee').post(function (req, res) {
 let employee = new employeeModel(req.body);
 employee.save()
 .then(game => {
 res.status(200).json({ 'employee': 'Employee Added Successfully' });
 })
 .catch(err => {
 res.status(400).send("Something Went Wrong");
 });
});

// To Get Employee Details By Employee ID
employeeRoute.route('/editEmployee/:id').get(function (req, res) {
 let id = req.params.id;
 employeeModel.findById(id, function (err, employee) {
 res.json(employee);
 });
});

// To Update The Employee Details
employeeRoute.route('/updateEmployee/:id').post(function (req, res) {
 employeeModel.findById(req.params.id, function (err, employee) {
 if (!employee)
 return next(new Error('Unable To Find Employee With This Id'));
 else {
 employee.firstName = req.body.firstName;
 employee.lastName = req.body.lastName;
 employee.email = req.body.email;
 employee.phone = req.body.phone;

 employee.save().then(emp => {
 res.json('Employee Updated Successfully');
 })
 .catch(err => {
 res.status(400).send("Unable To Update Employee");
 });
 }
 });
});

// To Delete The Employee
employeeRoute.route('/deleteEmployee/:id').get(function (req, res) {
 employeeModel.findByIdAndRemove({ _id: req.params.id }, function (err, employee) {
 if (err) res.json(err);
 else res.json('Employee Deleted Successfully');
 });
});

module.exports = employeeRoute;

In this file, I have done several configurations which are described below.

  • Imported some of the important packages

  • Used express as a web framework and routes to work with four different APIs for CRUD operations

  • Imported the employee model

  • Four types of routes with API function to perform CRUD operations into a single file

    Now our backend and the functionality for CRUD API are ready to use, and our next move is to test the implemented APIs.

Test REST Api’s

As far as our API will be implemented, it’s time to test or API's created for CRUD operation, for that open any API testing tool, here I am using Postman as an API testing tool to test the various HTTP based APIs.

Post Request

Get Request

Get by Id Request

Put Request

Delete Request

So this is how we have developed and tested our CRUD related APIs using the API testing tool Postman, now our backend is completely ready to use, it’s time to move into the Front-end part of our application where we will consume all the above APIs for the CRUD operations.

Front-end

In our front-end, we have used the Angular application, and for displaying employee records, we are using Angular material Datatable component. Few material components that we are going to use in the front-end application are given below.

  • Angular Material Datatable

  • Angular Material Card

  • Angular Material Paginator

  • Angular Material Sorting

  • Angular Material Form Fields (Input, Button, etc.) and many others as well

To create the components for CRUD operation, we need to create multiple components, for that, I would recommend creating a folder inside the app folder named /mean-stack-crud or any other suitable name of your choice then executing the series of commands to create the different components as given below.

ng generate component addEmployee
ng generate component editEmployee
ng generate component listEmployee

After executing the above npm commands, now we have our CRUD related components are created, but to call API from our back-end service, so for that create a new folder named \service and change your directory to a newly created folder and execute below npm command.

 ng generate service myDataService
So far we have created all the important components and also the service files to call REST API from the back-end services, next step is to configure routes to route through the different pages of the Angular application.

Route Configuration

To configure routes, create a new file into the app directory called routes.ts and paste the following code snippet.

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
import { MeanStackCrudComponent } from './mean-stack-crud/mean-stack-crud.component';

const appRoutes: Routes = [
 { path: '', redirectTo:'Crud',pathMatch:'full' },
 { 
 path: 'Crud', 
 loadChildren: './mean-stack-crud/index.module#MeanStackModule'
 },
 
];

export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
 

As you can see here I have used the loadChildren instead component because I have multiple components inside \mean-stack-crud components, so when the request goes to a mean-stack-crud component that it loads its own module runtime, it is called lazy loading. With the completion of the Routing configuration, a further step is to implement the services for our MEAN stack app.

Angular Service

We have already created a service file named my-data-service.service.ts, services are used to call the API from front-end to back-end server. And to implement services for CRUD operation just opens the file and paste the following code snippet.

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

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

 // Main api url to call api
 uri = 'http://localhost:4000/employees';

 constructor(private http: HttpClient) { }

 // To Get The List Of Employee
 getEmployees() {
 return this
 .http
 .get(`${this.uri}`);
 }

 // To Get Employee Details For Single Record Using Id
 getEmployeeById(empid) {
 return this.http.get(`${this.uri}/editEmployee/${empid}`);
 }

 // To Updated Specific Employee
 updateEmployee(id, body) {
 return this.http.post(`${this.uri}/updateEmployee/${id}`, body);
 }

 // To Create/Add New Employee
 addEmployee(body) {
 return this.http.post(`${this.uri}/addEmployee`, body);
 }

 // To Delete Any Employee
 deleteEmployee(empid) {
 return this.http.get(`${this.uri}/deleteEmployee/${empid}`);
 }

}

For the complete CRUD operation, in service, I have created a total five number of different service methods to call Nodejs REST API. That’s it for now, let’s summarized the things we have covered

  • We have created three different components to create, edit, and show the list of employees.

  • Created service to call REST APIs.

  • Router Configuration for routing through the different pages

  • Services File Implementation

Configure Home Page

Our entry point of application is the App component where we need to load the listing page for employees. So just open app.component.html and paste the following HTML code.

<div>
<router-outlet></router-outlet>
</div>

Here I have used a router-outlet that loads the view as per the routing configuration which loads the component based on the routes configured, and we have imported a few material components into root module files.

App.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { routing } from './routes';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { MeanStackCrudComponent } from './mean-stack-crud/mean-stack-crud.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Routes } from '@angular/router';
import { MatCardModule, MatToolbarModule, MatToolbar, MatButtonModule, MatButton, MatMenuModule, MatFormFieldModule, MatInputModule } from '@angular/material';
import { MatTableModule } from '@angular/material/table';
import { MatPaginatorModule } from '@angular/material/paginator';

@NgModule({
 declarations: [
 AppComponent,
 ],
 imports: [
 routing,
 BrowserModule,
 HttpClientModule,
 BrowserAnimationsModule, 
 MatCardModule,
 MatToolbarModule,
 MatButtonModule,
 MatMenuModule,
 MatFormFieldModule,
 MatTableModule,
 MatPaginatorModule,
 MatInputModule 
 ],
 exports: [
 BrowserModule, 
 MatCardModule,
 MatToolbarModule,
 MatButtonModule,
 MatMenuModule,
 MatFormFieldModule,
 MatTableModule,
 MatPaginatorModule,
 MatInputModule
],
 providers: [],
 bootstrap: [AppComponent]
})
export class AppModule { }

So far, we have configured routes and the configuration for the home page, and also the root module file, now when we run our example it will look for the mean-stack-crud component always so for that open mean-stack-crud folder and create a new file named index.module.ts and paste following code.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MeanStackCrudComponent } from './mean-stack-crud.component';
import { MatCardModule, MatToolbarModule, MatToolbar, MatButtonModule, MatButton, MatMenuModule, MatFormFieldModule, MatInputModule } from '@angular/material';
import { MatTableModule } from '@angular/material/table';
import { MatPaginatorModule } from '@angular/material/paginator';

const routes: Routes = [{
 path: "",
 component: MeanStackCrudComponent,
 children: [
 {
 path: "",
 loadChildren: './list-employee/index.module#ListEmployeeModule'
 },
 {
 path: "create",
 loadChildren: './add-employee/index.module#AddEmployeeModule'
 },
 {
 path: "edit/:id",
 loadChildren: './edit-employee/index.module#EditEmployeeModule'
 }
 ]
}];

@NgModule({
 imports: [
 CommonModule,
 FormsModule,
 ReactiveFormsModule,
 RouterModule.forChild(routes),
 MatCardModule,
 MatToolbarModule,
 MatButtonModule,
 MatMenuModule,
 MatFormFieldModule,
 MatTableModule,
 MatPaginatorModule,
 MatInputModule
 ],
 exports: [
 MatCardModule,
 MatToolbarModule,
 MatButtonModule,
 MatMenuModule,
 MatFormFieldModule,
 MatTableModule,
 MatPaginatorModule,
 MatInputModule
 ],
 declarations: [
 MeanStackCrudComponent
 ]
})
export class MeanStackModule { }

mean-stack-crud.component.html

<mat-card>
<div class="alert alert-info">
<strong>MEAN Stack - CRUD Operation</strong>
</div>
</mat-card>
<br/>
<mat-card>
<router-outlet></router-outlet>
</mat-card>

Let me explain that here mean-stack-crud is the main entry point of our CRUD operation where we have three different components, so when you see the routes in which I have specified the default route of list employee so once the application gets loaded, the first page will show the list of employees in the table.

Stylesheet For Whole Application

As we have discussed that we are using many angular material components, for that we are going to use some themes and custom CSS classes to beautify the material components. Specifically for this article, we are going to use the deeppurple-amber theme but you can use other themes as well which are given below.

Other themes

indigo-pink
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
pink-bluegrey
@import '~@angular/material/prebuilt-themes/pink-bluegrey.css';
purple-green
import '~@angular/material/prebuilt-themes/purple-green.css';

Open styles.css in \app directory and paste the following lines of code.

@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';

/* Custom CSS Classes */

.mat-card {
 text-align: -webkit-center;
}

.demo-toolbar {
 display: flex;
 align-items: center;
 width: 60%;
}

.demo-form {
 min-width: 150px;
 max-width: 500px;
 width: 100%;
}

.demo-full-width {
 width: 100%;
}

body {
 margin: 0;
 font-family: Roboto, sans-serif;
}

mat-card {
 max-width: 80%;
 margin: 2em auto;
 text-align: center;
}

mat-toolbar-row {
 justify-content: space-between;
}

.done {
 position: fixed;
 bottom: 20px;
 right: 20px;
 color: white;
}

.content-center {
 text-align: -webkit-center;
}

.alert {
 padding: 15px;
 margin-bottom: 20px;
 border: 1px solid transparent;
 border-radius: 4px;
}

.alert-info {
 color: #31708f;
 background-color: #d9edf7;
 border-color: #bce8f1;
}

strong {
 font-size: 30px;
}

/* Specific class for table */

.example-container[_ngcontent-c21] {
 display: flex;
 flex-direction: column;
 min-width: 300px;
}

.mat-elevation-z8 {
 box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12);
}

.mat-cell {
 text-align: -webkit-left;
}

.mat-header-cell {
 text-align: left;
}

img {
 border-radius: 20px;
 height: 70px;
}

/* End Table Class */

List Employee

Now we are going to show the list of all employees in the material data table. Create a new file called index.module.ts into a list-employee folder and paste the following code.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ListEmployeeComponent } from './list-employee.component';
import { MatCardModule, MatToolbarModule, MatToolbar, MatButtonModule, MatButton, MatMenuModule, MatFormFieldModule, MatInputModule , MatSortModule } from '@angular/material';
import { MatTableModule } from '@angular/material/table';
import { MatPaginatorModule } from '@angular/material/paginator';

const routes: Routes = [{
 path: "", 
 component: ListEmployeeComponent,
}];

@NgModule({
 imports: [
 CommonModule, 
 FormsModule, 
 ReactiveFormsModule, 
 RouterModule.forChild(routes),
 MatButtonModule,
 MatFormFieldModule,
 MatTableModule,
 MatPaginatorModule,
 MatInputModule,
 MatSortModule
 ],
 exports: [
 MatButtonModule,
 MatFormFieldModule,
 MatTableModule,
 MatPaginatorModule,
 MatInputModule,
 MatSortModule
 ],
 declarations: [
 ListEmployeeComponent
 ]
})
export class ListEmployeeModule {}

list-employee.component.html

<!-- For User ID -->
 <ng-container matColumnDef="lastName">
 <mat-header-cell *matHeaderCellDef mat-sort-header> Last Name </mat-header-cell>
 <mat-cell *matCellDef="let data"> {{data.lastName}} </mat-cell>
 </ng-container>

 <!-- For Title -->
 <ng-container matColumnDef="email">
 <mat-header-cell *matHeaderCellDef mat-sort-header> Email </mat-header-cell>
 <mat-cell *matCellDef="let data"> {{data.email}} </mat-cell>
 </ng-container>

 <!-- For Completion Status -->
 <ng-container matColumnDef="phone">
 <mat-header-cell *matHeaderCellDef mat-sort-header> Contact No </mat-header-cell>
 <mat-cell *matCellDef="let data"> {{data.phone}} </mat-cell>
 </ng-container>

 <!-- For Completion Status -->
 <ng-container matColumnDef="action">
 <mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
 <mat-cell *matCellDef="let data">
 <button mat-button color="primary" (click)="editEmployee(data._id)">Edit</button>
 <button mat-button color="warn" (click)="deleteEmployee(data._id)">Delete</button>
 </mat-cell>
 </ng-container>

 <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
 <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>

<!-- To paginate between pages with search -->
<mat-paginator #paginator [length]="employeeList && employeeList.length" [pageSize]="5" [pageSizeOptions]="[5, 10, 20]">
</mat-paginator>
</div>
<!-- </mat-card> -->

list-employee.component.ts

import { Component, OnInit, AfterViewInit, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
import { MyDataServiceService } from '../../Services/my-data-service.service';

export interface Employee {
 firstName: string;
 lastName: string;
 email: string;
 phone: string;
}

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

 @ViewChild(MatPaginator) paginator: MatPaginator;
 @ViewChild(MatSort) sort: MatSort;

 // Important objects
 MyDataSource: any;
 employeeList: Employee[];
 displayedColumns: string[] = ['firstName', 'lastName', 'email', 'phone', 'action'];

 constructor(private service: MyDataServiceService, private router: Router) {
 }

 ngOnInit() {
 this.getEmployees();
 }

 // To Get List Of Employee
 getEmployees() {
 this.service
 .getEmployees()
 .subscribe((data: Employee[]) => {
 this.MyDataSource = new MatTableDataSource();
 this.MyDataSource.data = data;
 this.MyDataSource.paginator = this.paginator;
 this.MyDataSource.sort = this.sort;
 });
 }

 // To Edit Employee
 editEmployee(empid) {
 this.router.navigate([`/Crud/edit/${empid}`]);
 }

 // Search specific result
 filterEmployee(searchstring: string) {
 searchstring = searchstring.trim();
 searchstring = searchstring.toLowerCase();
 this.MyDataSource.filter = searchstring;
 }
}

In this listing of employee components, basically, we have used Angular Material Datatable which lists the total number of employees, and apart from the listing, also implemented some other important functionality.

  • Filter records based on the specific search parameter

  • Sorting employees either ascending or descending

  • Pagination with total number of count, next and previous buttons, and the total number of results visible per page

    We are done with our listing of employee functionality; our next move is to create a new employee.

Create Employee

To create the new employee we need to have a form with submit button so that once the user adds the employee details, it will be saved into the database, so for that, I have used different material form controls.

  • Material form controls

  • Material Button Component

  • Material Card

  • Create index.module.ts inside the add-employee folder and paste the following code.

Index.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AddEmployeeComponent } from './add-employee.component';
import { MatButtonModule, MatButton, MatFormFieldModule, MatInputModule } from '@angular/material';

const routes: Routes = [{
 path: "", 
 component: AddEmployeeComponent,
}];

@NgModule({
 imports: [
 CommonModule, 
 FormsModule, 
 ReactiveFormsModule, 
 RouterModule.forChild(routes),
 MatButtonModule, MatFormFieldModule, MatInputModule
 ],
 exports: [
 MatButtonModule, MatFormFieldModule, MatInputModule
 ],
 declarations: [
 AddEmployeeComponent
 ]
})
export class AddEmployeeModule {}

add-employee.component.html

 <input formControlName="lastName" matInput placeholder="Last Name">
 </mat-form-field>
 <mat-error>
 <span *ngIf="!formGroup.get('lastName').valid && formGroup.get('lastName').touched">Please enter last name</span>
 </mat-error>
</td>
</tr>
<tr>
<td colspan="2">
 <mat-form-field class="demo-full-width">
 <input formControlName="email" matInput placeholder="Email">
 </mat-form-field>
 <mat-error>
 <span *ngIf="!formGroup.get('email').valid && formGroup.get('email').touched">Please enter email</span>
 </mat-error>
</td>
</tr>
<tr>
<td colspan="2">
 <mat-form-field class="demo-full-width">
 <input formControlName="phone" matInput placeholder="Contact No">
 </mat-form-field>
 <mat-error>
 <span *ngIf="!formGroup.get('phone').valid && formGroup.get('phone').touched">Please enter contact no</span>
 </mat-error>
</td>
</tr>
<tr>
<td colspan="2" class="content-center">
 <button mat-raised-button color="accent" [disabled]="!formGroup.valid">Submit</button>
</td>
</tr>
<tr>
<td></td>
</tr>
</table>
</form>

add-employee.component.ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { FormsModule, FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { MyDataServiceService } from '../../Services/my-data-service.service';

@Component({
 selector: 'app-add-employee',
 templateUrl: './add-employee.component.html',
})
export class AddEmployeeComponent implements OnInit {

 formGroup: FormGroup;

 constructor(private formBuilder: FormBuilder, private service: MyDataServiceService, private router: Router) { }

 ngOnInit() {
 this.initializeForm();
 }

 // To initialize Form
 initializeForm() {
 this.formGroup = this.formBuilder.group({
 firstName: ['', [Validators.required]],
 lastName: ['', [Validators.required]],
 email: ['', [Validators.required]],
 phone: ['', [Validators.required]],
 });
 }

 // Add Employee When Submit Button Is Clicked
 addEmployee() {
 if (this.formGroup.valid) {
 let data = this.formGroup.value;
 this.service.addEmployee(data).subscribe(() => {
 this.router.navigate(['/Crud']);
 });
 }
 }

}

In this component of Create employee, we have created a reactive form using multiple Angular Material Form components, and when the user submits the form it will call the service and a new employee will be created.

Update Employee

When the user wants to update the record and click on the edit button from the list of the employee data table, the new component comes into the picture with the form and the values that the user has created already. Create an index.module.ts file inside the edit-employee folder and paste the following code into the file.

Index.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { EditEmployeeComponent } from './edit-employee.component';
import { MatButtonModule, MatButton, MatFormFieldModule, MatInputModule } from '@angular/material';

const routes: Routes = [{
 path: "", 
 component: EditEmployeeComponent,
}];

@NgModule({
 imports: [
 CommonModule, 
 FormsModule, 
 ReactiveFormsModule, 
 RouterModule.forChild(routes),
 MatButtonModule,
 MatFormFieldModule,
 MatInputModule
 ],
 exports: [
 MatButtonModule,
 MatFormFieldModule,
 MatInputModule
 ],
 declarations: [
 EditEmployeeComponent
 ]
})
export class EditEmployeeModule {}

edit-employee.component.html

</mat-form-field>
<mat-error>
 <span *ngIf="!frmGroup.get('lastName').valid && frmGroup.get('lastName').touched">Please enter last name</span>
</mat-error>
</td>
</tr>
<tr>
<td colspan="2">
<mat-form-field class="demo-full-width">
 <input formControlName="email" matInput placeholder="Email">
</mat-form-field>
<mat-error>
 <span *ngIf="!frmGroup.get('email').valid && frmGroup.get('email').touched">Please enter email</span>
</mat-error>
</td>
</tr>
<tr>
<td colspan="2">
<mat-form-field class="demo-full-width">
 <input formControlName="phone" matInput placeholder="Contact No">
</mat-form-field>
<mat-error>
 <span *ngIf="!frmGroup.get('phone').valid && frmGroup.get('phone').touched">Please enter contact no</span>
</mat-error>
</td>
</tr>
<tr>
<td colspan="2" class="content-center">
<button mat-raised-button color="accent" [disabled]="!frmGroup.valid">Submit</button>
</td>
</tr>
<tr>
<td></td>
</tr>
</table>
</form>

edit-employee.component.ts

import { Component, OnInit } from '@angular/core';
import { MyDataServiceService } from '../../Services/my-data-service.service';
import { Router, ActivatedRoute } from '@angular/router';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import Employee from '../../../../Model/Employee';

@Component({
 selector: 'app-edit-employee',
 templateUrl: './edit-employee.component.html',
})
export class EditEmployeeComponent implements OnInit {

 empid: string;
 employeeDetail: Employee;
 frmGroup: FormGroup;

 constructor(private service: MyDataServiceService, private formBuilder: FormBuilder, private router: Router, private activatedRoute: ActivatedRoute) {
 this.activatedRoute.params.subscribe(params => {
 this.empid = params.id;
 });
 this.initializeForm();
 }

 ngOnInit() {
 this.getEmployeeById(this.empid);
 }

 // To Initialize Form
 initializeForm() {
 this.frmGroup = this.formBuilder.group({
 firstName: ['', [Validators.required]],
 lastName: ['', [Validators.required]],
 email: ['', [Validators.required]],
 phone: ['', [Validators.required]],
 });
 }

 // To Single Employee Details By ID
 getEmployeeById(empid) {
 this.service.getEmployeeById(empid).subscribe(res => {
 this.employeeDetail = res;
 this.frmGroup.patchValue({
 firstName: this.employeeDetail.firstName,
 lastName: this.employeeDetail.lastName,
 email: this.employeeDetail.email,
 phone: this.employeeDetail.phone,
 });
 });
 }

 // To Update Employee Detail
 updateEmployee() {
 if (this.frmGroup.valid) {
 let data = this.frmGroup.value;
 this.service.updateEmployee(this.empid, data).subscribe(() => {
 this.router.navigate(['/Crud']);
 });
 }
 }

}

In the edit employee page, we have a form similar to the create employee page but in the edit form, we are getting the values of the selected employee record from REST API and binding it to the form elements, and whenever a user submits the form, the data will be updated.

Delete Employee

In this article, there is no separate page for the delete operation, but on the employee list page, we need to add one more function which calls the service method and passes the employee id as a parameter. Open list-employee.ts and add the following method.

// Delete Employee
 deleteEmployee(empid) {
 this.service.deleteEmployee(empid).subscribe(() => {
 this.getEmployees();
 });
 }

After adding the above method, we can delete an employee by clicking on the delete button which is present in the employee list data table which was already implemented. We are done with our front-end configuration for all the CRUD operations-related components/pages, now it’s time to execute the application and test all the implemented functionality one by one.

Running MEAN Stack App

Open PowerShell in visual studio code and use the following command
ng serve -o
Open another PowerShell window and execute the following code to start the express server
>node server.js

How it Works.

Create Operation

Click on Add New Employee button and the form will have appeared on the screen as given below.

Read Operation

When we execute the application, you will be redirected to this default page which lists out the number of employees along with the button to create the new employee.

Edit Operation

When you click on the edit button from the material table, it will open a new page to update the existing record.

Delete Operation

To delete an employee just we need to click on the delete button and then the specific record will be removed from the database.

Important Note

This example shows the basic implementation of using CRUD operation, and this is not the only way to achieve it, hence, this example can be improved with the multiple advances and robust concepts which are given below.

  1. Add error handling module to handle run-time errors and to inform about the same the end-user

  2. Show toaster notification as soon as the status change in between the user interactivity

  3. Better user experience using the advanced UI/UX setup

  4. And many more feature enhancements can be done as per the business needs

Summary

In the end, you have completed the MEAN Stack application with different JavaScript technologies like Angular, Nodejs, expressjs, and MongoDB. Bu using the MEAN stack mechanism we can achieve higher performance, robustness, and reusable components. Try to play with the code that we have implemented and do modifications as per your requirements, I hope you have learned something from this MEAN stack guide, Happy coding then.

Share Article
About Author
Manav Pandya (Technical Author and Front-end Engineer)

Manav is Blogger, Technical Author, Freelancer, and working as a front-end engineer since last 2 year with the different technologies like Angular 2+, Node.js, React, ExpressJs, In a free time he likes to learn and contribute technical content to the community to share and spread the knowledge.
Accept cookies & close this