MEAN Stack CRUD Operations Using Angular Material Datatable

Manav Pandya   Source Code  Print 
06 Sep 2018
12 Sep 2018
Advanced
964

In this part of the article, we are going to learn the CRUD operations using MEAN stack with the Angular Material Data table component. Let's understand the MEAN Stack.

MEAN Stands for:

M - MongoDB

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

E - ExpressJs

ExpressJs is a Web application framework which 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 which is used to create single page application.

N – Nodejs

Nodejs is a JavaScript runtime which 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 high scalable web and mobile compatible application 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.

Front-end Project

For the front-end, we are using Angular 6 application which contains the structure like this. Primarily we are going to use three primary components to work with CRUD operations, at the end main advantage is to achieve re-usability of the component.

Server Side

And for server side, we are using server configuration, routes, models etc. So for that, I have basically created the three different folders Model, Routes and Server respectively.

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

Prerequisites

To work with MEAN Stack, we need to have few tools to be installing.

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 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 than download and configure the above tools wisely.

Setup and Installation

After installing the above-listed tools, now it’s time to install a few dependencies which we are using throughout in this article for both 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 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 Angular Material Datatable to list the employees, so for that, we are using Angular Material Component and need to install the following dependencies.

Npm command
Usage
Npm install @angular/material
To use all the angular material components into 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 important dependencies which we are using in this MEAN Stack app, now it’s time to implement CRUD operation step by step.

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 necessary settings to the application, for that just create a new folder named Server and inside the folder create a file named server.js and paste the following code.

 // 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 into the above server file, we have included many npm packages, express server configuration, route configuration, data formatter etc. In above file I have already included 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 database URL and at the end, we are going to connect MongoDB database by using connect() method.

MongoDB Model Schema

In this article, we are going to use schema for Employee management, which will allow us to create 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.

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 MongoDB collection schema in which I have added four different columns with the appropriate data type.

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 operation. To work with MongoDB user document, we need to have an API controller which allow us to use different routes for CRUD operations. Create folder named Routes and inside folder create a new file named Employee.route.js and paste the following code.

// 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 things which are described below.

  • Imported some of the important packages

  • Used express as web framework and routes

  • Imported 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 is ready to use, our next move is to test the implemented API’s.

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 API testing tool.

Post Request

Get Request

Get by Id Request

Put Request

Delete Request

So this is how we have developed and tested our CRUD related API's using 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.

Front-end

In our front-end, we have used Angular 6 application, and for displaying employee’s records, we are using Angular material Datatable. Few material components that we have used in the front end 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 app folder named mean-stack-crud or any other name of your choice then execute series of commands given below.

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

After executing above npm commands, now we have our CRUD related files are created, but to call API from MongoDB, 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 service file to call REST API from MongoDB, next step is to configure routes.

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 that here I have used 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 Routing configuration, a further step is to implement the services for our MEAN stack app.

Angular Service

We have already created 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 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 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 list employee.

  • Created service to call REST APIs.

  • Route Configuration

  • 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 following HTML code.

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

Here I have used router-outlet which loads the view as per the routing configuration, and we have imported 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 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 default route for list employee.

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 CSS class. Specifically for this article, we are going to use the deeppurple-amber theme but you can use other themes as well which are listed below.

Other themes

indigo-pnk
@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 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 list 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 component, 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

  • Sorting employee

  • 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 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 many Angular Material Form components, and when the user submits the form it will call the service and new employee will be created.

Update Employee

When the user wants to update the record and click on 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 inde.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 edit employee page, we have a form something like create operation but in the edit form, we are getting the value from REST API and binding it to form, and whenever a user submits the form, the data will be updated.

Delete Employee

In this article, there is no a separate page for the delete operation, but in employee list page we need to add one more method which calls the service method and passes the employee id as 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 any employee by clicking on delete button which is present in employee list data table already implemented. We are done with our front-end configuration for all the CRUD operations, now it’s time to execute the application and test all the implemented functionality.

Running MEAN Stack App

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

How it Works..

Create Operation

Click on Add New Employee button and you will get the output like this.

Read Operation

When you execute the application, you will be redirected to this page which lists out the number of employees.

Edit Operation

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

Delete Operation

To delete an employee just we need to click on delete button.

Important Note

This example is just for the step by step learning purpose, you can expand it limitless.

  1. Add error handling module

  2. Show toaster notification

  3. Better user experience

  4. And many more feature enhancement

Summary

In the end, you have completed the MEAN Stack application with different JavaScript technologies like Angular 6, 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 modification as per your requirements, I hope you have learned something from this MEAN stack guide, Happy coding then.

Hands-on Learning
Free Interview Books
 
+