TechieClues TechieClues
Updated date Mar 13, 2024
In this article, we will see how to integrate the RESTful API CRUD operations (Create, Retrieve, Update, and Delete) which we learned in part 1 into the angular front-end. We will create and design the HTML and typescript files and update the configurations and finally will integrate the CRUD operation on the client-side.

Download File(s):

AspNetCore_AngularApp.rar

Introduction

Let's set up the angular application and design the web page where we create, retrieve, update, and delete details. We have RESTful API API with CRUD operations which we discussed in the article part 1. If you haven't read Part 1, then please go through the article Create and Build an ASP.NET Core Angular CRUD Application - Part 1.

We have an angular template already created with the ASP.NET Core template by Visual Studio. You will see the "ClientApp" folder in our solution as shown below, Which has the angular files (HTML, typescript, and config) and node modules.

We are not going to use the predefined components and routes. We will use the app.component to design our page and integrate the CRUD operations (RESTful API).

Step 1: Install Required Packages

Before going to design our app, we need to install @angular/material and require dependencies. Go to the root folder of the angular application open Powershell and use the below commands to install the latest version of the material.

# Install the latest version
npm install --save @angular/material @angular/cdk @angular/animations

# Install Angular Material version 8  (Note : I have used Angular 8 so I mentioned the version as 8 for angular material)
npm install --save @angular/material@8 @angular/cdk@8 @angular/animations@8

Step 2: Add Material Theme in Style.css

Add the below line at the top of the Style.css file so that it will be used for the entire application if you want.

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

Step 3: Import BrowserAnimationsModule

Go to app.module file then import BrowserAnimationsModule then add in imports array as shown below,

app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    CounterComponent,
    FetchDataComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    BrowserAnimationsModule,  
    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full' },
      { path: 'counter', component: CounterComponent },
      { path: 'fetch-data', component: FetchDataComponent },
    ])
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 4: Import Material Modules

We will use TableDialogFormFieldsInput, and Buttons as Material components in this article. To use the material components, we should import these components in the app.module.ts file and add to the imports array to use them in our application.

app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { 
  MatTableModule, 
  MatDialogModule, 
  MatFormFieldModule,
  MatInputModule,
  MatButtonModule
} from '@angular/material';

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    CounterComponent,
    FetchDataComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    BrowserAnimationsModule,
    MatTableModule,
    MatDialogModule,
    MatFormFieldModule,
    MatInputModule,
    MatButtonModule,
    MatInputModule,
    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full' },
      { path: 'counter', component: CounterComponent },
      { path: 'fetch-data', component: FetchDataComponent },
    ])
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 5: Create a Material Table and Controls

In our example, We will use employee details and how to create, update, and delete employee details & retrieve all the employees, and display it in the table.

We will use SPA(Single Page Application) to consume all the operations such as CRUD (Create Retrieve, Update, and Delete). Below the code, you can see the Material Table directive in app.component.html

app.component.html:

#mytable is a template variable that is used to refresh table data by calling renderRows() method. *matHeaderRowDef is used to render an array of columns that we want to display in the table. matColumnDef property on the column is the same as a key in the JSON data object. *matHeaderCellDef has the text of columns in the table header.

<div class="container">
  <button mat-button (click)="openDialog('Add',{})" mat-flat-button color="primary">Add Employee</button>
  <table mat-table [dataSource]="dataSource" #mytable class="my-table mat-elevation-z8">
    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef> Name </th>
      <td mat-cell *matCellDef="let element"> {{element.name}} </td>
    </ng-container>

    <ng-container matColumnDef="age">
      <th mat-header-cell *matHeaderCellDef> Age </th>
      <td mat-cell *matCellDef="let element"> {{element.age}} </td>
    </ng-container>

    <ng-container matColumnDef="designation">
      <th mat-header-cell *matHeaderCellDef> Designation </th>
      <td mat-cell *matCellDef="let element"> {{element.designation}} </td>
    </ng-container>


    <ng-container matColumnDef="mobileNumber">
      <th mat-header-cell *matHeaderCellDef> MobileNumber </th>
      <td mat-cell *matCellDef="let element"> {{element.mobileNumber}} </td>
    </ng-container>

    <ng-container matColumnDef="action">
      <th mat-header-cell *matHeaderCellDef> Action </th>
      <td mat-cell *matCellDef="let element" class="action-link"> 
        <a (click)="openDialog('Update',element)">Edit</a> | 
        <a (click)="openDialog('Delete',element)">Delete</a>  
      </td>
    </ng-container>

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

app.component.ts:

import { Component, ViewChild, Inject } from '@angular/core';
import { MatDialog, MatTable } from '@angular/material';
import { DialogBoxComponent } from './dialog-box/dialog-box.component';
import { HttpClient } from '@angular/common/http';

export interface UsersData {
  name: string;
  id: number;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})

export class AppComponent {
  displayedColumns: string[] = ['name', 'age', 'designation', 'mobileNumber', 'action'];
  dataSource: any;  
  public employee: Employee;
  @ViewChild(MatTable,{static:true}) table: MatTable<any>;

  constructor(public dialog: MatDialog, public http: HttpClient, @Inject('BASE_URL') public baseUrl: string) {
    http.get<Employee[]>(baseUrl + 'api/employees').subscribe(result => {
       this.dataSource = result;
    }, error => console.error(error));
  }

  openDialog(action,obj) {
    obj.action = action;
    const dialogRef = this.dialog.open(DialogBoxComponent, {
      width: '300px',
      data:obj
    });

    dialogRef.afterClosed().subscribe(result => {
      if(result.event == 'Add'){
        this.addRowData(result.data);
      }else if(result.event == 'Update'){
        this.updateRowData(result.data);
      }else if(result.event == 'Delete'){
        this.deleteRowData(result.data);
      }
    });
  }

  addRowData(newRow){  
    this.dataSource.push({      
      name:newRow.name,
      age:newRow.age,
      designation:newRow.designation,
      mobileNumber:newRow.mobileNumber
    });

    this.employee = {       
       name:newRow.name,
       age: parseInt(newRow.age),
       designation:newRow.designation,
       mobileNumber:parseInt(newRow.mobileNumber)
    };
    const headers = { 'content-type': 'application/json'}  
    const body=JSON.stringify(this.employee);
    this.http.post<Employee>(this.baseUrl + 'api/Employees', body , {'headers':headers}).subscribe(data => {        
    })

    this.table.renderRows();
    
  }
  updateRowData(newRow){
    this.dataSource = this.dataSource.filter((value,key)=>{
      if(value.id == newRow.id){
          value.name = newRow.name;
          value.age=newRow.age;
          value.designation=newRow.designation;
          value.mobileNumber=newRow.mobileNumber;
      }

      this.employee = {    
        id: newRow.id,
        name:newRow.name,
        age: parseInt(newRow.age),
        designation:newRow.designation,
        mobileNumber:parseInt(newRow.mobileNumber)
      };
      const headers = { 'content-type': 'application/json'}  
      const body=JSON.stringify(this.employee);
      this.http.put<Employee[]>(this.baseUrl + 'api/Employees/' + newRow.id, body , {'headers':headers}).subscribe(data => {         
      })
      return true;
    });
  }
  deleteRowData(newRow){
    this.dataSource = this.dataSource.filter((value,key)=>{
       this.http.delete<any>(this.baseUrl + 'api/Employees/' + newRow.id).subscribe(data => {         
      })
      return value.id != newRow.id;
    });
  }
}


interface Employee {
  id: string;
  name: number;
  age: number;
  designation: string;
  mobileNumber: string;
}

Add component dialog box by using the below command,

$ ng generate component dialog-box

Once you have generated the dialog box component, then the component details will be updated in app.module.ts file as shown below,

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { DialogBoxComponent } from './dialog-box/dialog-box.component';

import { 
  MatTableModule, 
  MatDialogModule, 
  MatFormFieldModule,
  MatInputModule,
  MatButtonModule
} from '@angular/material';

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    CounterComponent,
    FetchDataComponent,
    DialogBoxComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    BrowserAnimationsModule,
    MatTableModule,
    MatDialogModule,
    MatFormFieldModule,
    MatInputModule,
    MatButtonModule,
    MatInputModule,
    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full' },
      { path: 'counter', component: CounterComponent },
      { path: 'fetch-data', component: FetchDataComponent },
    ])
  ],
   entryComponents: [
    DialogBoxComponent
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Add below code in dialog-box.component.html

<h1 mat-dialog-title><strong>{{action}} Employee</strong></h1>
<div mat-dialog-content>
  <mat-form-field *ngIf="action != 'Delete'; else elseTemplate">
    <input placeholder="Name" matInput [(ngModel)]="local_data.name">    
  </mat-form-field>
  <mat-form-field *ngIf="action != 'Delete'; else elseTemplate">
    <input placeholder="Age" matInput [(ngModel)]="local_data.age">  
  </mat-form-field>
  <mat-form-field *ngIf="action != 'Delete'; else elseTemplate">
    <input placeholder="Designation" matInput [(ngModel)]="local_data.designation">
  </mat-form-field>
  <mat-form-field *ngIf="action != 'Delete'; else elseTemplate">
    <input placeholder="Mobile Number" matInput [(ngModel)]="local_data.mobileNumber">
  </mat-form-field>
  <div *ngIf="action == 'Delete'">Are you sure you want to delete "{{local_data.name}}"?</div>  
</div>
<div mat-dialog-actions>
  <button mat-button (click)="doAction()">{{action}}</button>
  <button mat-button (click)="closeDialog()" mat-flat-button color="warn">Cancel</button>
</div>

Add the below code in dialog-box.component.ts

import { Component, Inject, Optional } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';

export interface UsersData {
  name: string;
  id: number;
}
@Component({
  selector: 'app-dialog-box',
  templateUrl: './dialog-box.component.html',
  styleUrls: ['./dialog-box.component.css']
})
export class DialogBoxComponent {
  action:string;
  local_data:any;
  constructor(
    public dialogRef: MatDialogRef<DialogBoxComponent>,    
    @Optional() @Inject(MAT_DIALOG_DATA) public data: UsersData) {
    console.log(data);
    this.local_data = {...data};
    this.action = this.local_data.action;
  }
  doAction(){
    this.dialogRef.close({event:this.action,data:this.local_data});
  }
  closeDialog(){
    this.dialogRef.close({event:'Cancel'});
  }
}

Screenshots:

Add Employee:

Once you have entered and clicked the "Add" button the Post method will be called and the employee data will be inserted into the database and displayed on the screen as shown below,

Update Employee:

Click edit the employee, click the edit button and update the employee details as shown below,

Delete Employee:

ABOUT THE AUTHOR

TechieClues
TechieClues

I specialize in creating and sharing insightful content encompassing various programming languages and technologies. My expertise extends to Python, PHP, Java, ... For more detailed information, please check out the user profile

https://www.techieclues.com/profile/techieclues

Comments (15)

  • Tomislav Dunaj
    Tomislav Dunaj 02 Jan, 2021

    Very nice tutorial. Problem is I stuck on adding component dialog box ("ng generate component dialog-box"). I got error: "The generate command requires to be run in an Angular project, but a project definition could not be found." I did a lot of searching on the Internet and couldn't get solution. Please, help me to resolve it. Tom

    • Elin Ekman

      Elin Ekman 11 Feb, 2021

      This worked for me: ng generate component componentName --module=app.module

  • TechieClues
    TechieClues 03 Jan, 2021

    Thanks. Please check your Angular/CLI version (use the command: ng version). I have used the "8.2.12" angular version in this project. so If your version is lower than this version. please update it (use the command: npm install -g @angular/cli). I have attached the source of this tutorial. Please download it and check.

  • Aastha Pathak
    Aastha Pathak 03 Feb, 2021

    Thank you for the tutorial sir, but I am getting "AggregateException: One or more errors occurred. (One or more errors occurred. (The NPM script 'start' exited without indicating that the Angular CLI was listening for requests. The error output was: An unhandled exception occurred: Job name "..getProjectMetadata" does not exist." Can you please help with this

    • TechieClues

      TechieClues 05 Feb, 2021

      Hi Aastha, Thanks for reading this article. Please find the link below, https://www.techieclues.com/questions/the-npm-script-start-exited-without-indicating-that-the-angular-cli-was-listening-for-requests

  • ben hudson
    ben hudson 11 Mar, 2021

    I'm having the same issue as Tomislav. I have the CLI v11.0.2 installed.

    • TechieClues

      TechieClues 18 Mar, 2021

      Please check your Angular/CLI version (use the command: ng version). I have used the "8.2.12" angular version in this project. so If your version is lower than this version. please update it (use the command: npm install -g @angular/cli). I have attached the source of this tutorial. Please download it and check.

  • Tara King
    Tara King 13 Sep, 2021

    I am getting the error "@angular/material" has no exported member on all of the material items I am trying to import in, material and cdk are both listed in package.json and I am not having that issue with animations, any idea why this is happening?

    • TechieClues

      TechieClues 16 Sep, 2021

      Please remove package-lock.json and node modules. And run npm install again.

  • SHEHAN UDARAKA
    SHEHAN UDARAKA 16 Sep, 2021

    Hi I have a error of app.component.ts file. It is TS type 'number' is not assignable to type 'string'. How to fix this error?

    • TechieClues

      TechieClues 16 Sep, 2021

      Please raise your questions with your exact code here. https://www.techieclues.com/questions.

  • Saurabh Kumar
    Saurabh Kumar 16 Nov, 2021

    Hi I have a error of app.component.ts file. It is TS type 'number' is not assignable to type 'string'. How to fix this error?

    • TechieClues

      TechieClues 17 Nov, 2021

      I am not sure how do you implement your code. But please check here for the explicit declaration - https://stackoverflow.com/questions/48670111/typescript-type-number-is-not-assignable-to-type-string

  • NICHOLAS FLEETWOOD
    NICHOLAS FLEETWOOD 18 May, 2022

    When I import materials, I am getting error "@angular/materials has no exported member MatFormFieldModule". I see this was an earlier question, but I am not sure how to "remove ... node modules". can you specify?