CRUD Operation In Angular 6

In this article, we will be building an Angular 6 application and will perform a CRUD Operation step by step from scratch with an example. We will be generating our Angular 6 application using Angular CLI and then modify it to have an employee management project where the end-user can perform CRUD operations, i.e., Create, List, Update, and Delete with the sample REST API exposed using HttpClientModule. We will also be using RouterModule to have the routing enabled.

For this project, I have npm 5.6.0 and node v8.11.2 installed on my local system. You can download the latest version of Node from here. To update NPM, you can run the following command in the terminal.

npm install npm@latest -g

If you have the @angular/cli version older than 6, then run the following command to install the latest version.

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

To install a specific version, you can use this command.

npm install -g @angular/[email protected]

Generating Angular 6 Project

Once the npm and node are upgraded to the latest version, you can run the following command to generate an Angular 6 project in any location of your choice.

ng new crudoperation

Doing so, our Angular 6 application is generated.

Angular 6 Project Structure

Once the project is generated, you can run the following commands to see the Angular 6 app running at localhost:4200.

cd crudoperation
ng serve

 Project Structure

Routing

Following is our routing configuration. We have configured it to use ListEmpComponent as a default component. Also, do not forget to include it in the main module - app.module.ts.

app-routing.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { ListEmpComponent } from './list-emp/list-emp.component';
import { AddEmpComponent } from './add-emp/add-emp.component';

export const routes: Routes = [
  { path: '', component: ListEmpComponent, pathMatch: 'full' },
  { path: 'list-emp', component: ListEmpComponent },
  { path: 'add-emp', component: AddEmpComponent }
];

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forRoot(routes)
  ],
  exports: [RouterModule],
  declarations: []
})
export class AppRoutingModule { }

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { ReactiveFormsModule } from "@angular/forms";

import { AppComponent } from './app.component';
import { ListEmpComponent } from './list-emp/list-emp.component';
import { AddEmpComponent } from './add-emp/add-emp.component';
import { EmployeeService } from './service/employee.service';

@NgModule({
  declarations: [
    AppComponent,
    ListEmpComponent,
    AddEmpComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    AppRoutingModule,
    ReactiveFormsModule
  ],
  providers: [EmployeeService],
  bootstrap: [AppComponent]
})
export class AppModule { }

// Model
export class Employee {
  id?: number;
  employee_name?: string;
  employee_salary?: number;
  employee_age?: number;
}

Following is the implementation of our EmployeeService. It has all the API details that are required for the CRUD operation. Here, I have used JSON Server for making API calls. The JSON Server is for front-end developers, which simulates a back-end REST Service to deliver the data in JSON format to the front-end application and make sure everything is working as expected.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Employee } from '../model/employee.model';

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

  constructor(private http: HttpClient) { }

  baseUrl: string = 'http://localhost:3004/posts/';

  getEmployees() {
    return this.http.get<Employee[]>(this.baseUrl);
  }

  deleteEmployees(id: number) {
    return this.http.delete<Employee[]>(this.baseUrl + id);
  }

  createUser(employee: Employee) {
    return this.http.post(this.baseUrl, employee);
  }

  getEmployeeById(id: number) {
    return this.http.get<Employee>(this.baseUrl + '/' + id);
  }

  updateEmployee(employee: Employee) {
    return this.http.put(this.baseUrl + '/' + employee.id, employee);
  }
}

Creating Components list-emp.component.html.

<div class="col-md-12">
  <h2>User Details</h2>
  <div class="table-responsive table-container">
    <table class="table">
      <thead>
        <tr>
          <th>Id</th>
          <th>Employee Name</th>
          <th>Salary</th>
          <th>Age</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let emp of employees">
          <td class="hidden">{{ emp.id }}</td>
          <td>{{ emp.employee_name }}</td>
          <td>{{ emp.employee_salary }}</td>
          <td>{{ emp.employee_age }}</td>
          <td>
            <button (click)="deleteEmp(emp)" class="btn btn-info"> Delete </button>
            <button (click)="editEmp(emp)" style="margin-left: 20px;" class="btn btn-info"> Edit </button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

list-emp.component.ts

import { Component, OnInit } from '@angular/core';
import { EmployeeService } from '../service/employee.service';
import { Employee } from '../model/employee.model';
import { Router } from "@angular/router";

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

  employees: Employee[];

  constructor(private empService: EmployeeService, private router: Router) { }

  ngOnInit() {
    this.empService.getEmployees()
      .subscribe((data: Employee[]) => {
        this.employees = data;
      });
  }

  deleteEmp(employee: Employee): void {
    this.empService.deleteEmployees(employee.id)
      .subscribe(data => {
        this.employees = this.employees.filter(u => u !== employee);
      });
  }

  editEmp(employee: Employee): void {
    localStorage.removeItem('editEmpId');
    localStorage.setItem('editEmpId', employee.id.toString());
    this.router.navigate(['add-emp']);
  }

}

add-emp.component.html

<div class="col-md-6">
  <h2 class="text-center">{{ empformlabel }}</h2>
  <form [formGroup]="addForm" novalidate class="form">
    <div class="form-group">
      <label for="empId">Employee Id:</label>
      <input type="number" formControlName="id" placeholder="Id" name="empId" class="form-control" id="empId">
    </div>

    <div class="form-group">
      <label for="empName">Employee Name:</label>
      <input formControlName="employee_name" placeholder="Employee Name" name="empName" class="form-control" id="empName">
      <div class="alert alert-danger" *ngIf="addForm.get('employee_name').hasError('required') && addForm.get('employee_name').touched">
        Employee Name is required
      </div>
    </div>

    <div class="form-group">
      <label for="empSalary">Employee Salary:</label>
      <input formControlName="employee_salary" placeholder="Employee Salary" name="employee_salary" class="form-control" id="employee_salary">
      <div class="alert alert-danger" *ngIf="addForm.get('employee_salary').hasError('maxlength') && addForm.get('employee_salary').touched">
        Employee Salary is required and should be less than 9 characters.
      </div>
    </div>

    <div class="form-group">
      <label for="empAge">Employee Age:</label>
      <input formControlName="employee_age" placeholder="Employee Age" name="empAge" class="form-control" id="empAge">
      <div class="alert alert-danger" *ngIf="addForm.get('employee_age').hasError('maxlength') && addForm.get('employee_age').touched">
        Age is required and should be less than 3 characters.
      </div>
    </div>

    <button class="btn btn-success" [disabled]="addForm.invalid" *ngIf="btnvisibility" (click)="onSubmit()">Save</button>
    <button class="btn btn-success" [disabled]="addForm.invalid" *ngIf="!btnvisibility" (click)="onUpdate()">Update</button>

    <p>Form value: {{ addForm.value | json }}</p>
  </form>
</div>

add-emp.component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { EmployeeService } from '../service/employee.service';
import { Router } from "@angular/router";

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

  empformlabel: string = 'Add Employee';
  empformbtn: string = 'Save';

  constructor(private formBuilder: FormBuilder, private router: Router, private empService: EmployeeService) { }

  addForm: FormGroup;
  btnvisibility: boolean = true;

  ngOnInit() {
    this.addForm = this.formBuilder.group({
      id: [],
      employee_name: ['', Validators.required],
      employee_salary: ['', [Validators.required, Validators.maxLength(9)]],
      employee_age: ['', [Validators.required, Validators.maxLength(3)]]
    });

    let empid = localStorage.getItem('editEmpId');
    if (+empid > 0) {
      this.empService.getEmployeeById(+empid).subscribe(data => {
        this.addForm.patchValue(data);
      });
      this.btnvisibility = false;
      this.empformlabel = 'Edit Employee';
      this.empformbtn = 'Update';
    }
  }

  onSubmit() {
    console.log('Create fire');
    this.empService.createUser(this.addForm.value)
      .subscribe(data => {
        this.router.navigate(['list-emp']);
      },
      error => {
        alert(error);
      });
  }

  onUpdate() {
    console.log('Update fire');
    this.empService.updateEmployee(this.addForm.value).subscribe(data => {
      this.router.navigate(['list-emp']);
    },
    error => {
      alert(error);
    });
  }

}

Global Style style.css

/* You can add global styles to this file, and also import other style files */

@import "~bootstrap/dist/css/bootstrap.css";
@import "~font-awesome/css/font-awesome.css";

.ng-valid[required],
.ng-valid.required {
  border-left: 5px solid #42A948; /* green */
}

.ng-invalid:not(form) {
  border-left: 5px solid #a94442; /* red */
}

.mtop10 {
  margin-top: 10px;
}

Testing Angular 6 Application

Now, run the command ng serve and hit localhost:4200.

You can see the following screen with a list of users. On this page, you can perform actions to add, edit, and delete an employee.

Testing Angular

Edit Employee

Add Employee

Here, we have used the same component to Add and Edit/Update the Employee.

Conclusion

In this article, we learned about Angular 6 CRUD operations and created a demo application. The source can be downloaded from GitHub here.