Contact Application Using ASP.NET Core Web API, Angular 6.0, And Visual Studio Code - Part Two

In this article, we are going to learn about how we can setup Angular 6.0 in ASP.Net Core Web API project and develop the contact list & form component using Angular Material UI.

 

 

To setup Angular 6.0 in the project, first, we have to install NodeJS in the development environment. We can download NodeJS installer from NodeJS website. and then check the version on NodeJS as below.

Now, let us globally install Angular CLI package by enter “npm install –g angular/[email protected]”, as shown in below screenshot.

 

Scaffold Angular

To scaffold Angular, enter “ng new Contact-App --skip-install” command in VS code terminal as below.

 

Here, --skip-install option is used to skip installation of the npm packages. And Contact-App is our Angular app name.

After the project is created, we move all the files & folders from Contact-App to Root folder as below:

 
 
Then we enter ‘npm install’ command in terminal to install all required packages for Angular. 
 
 

Change Angular Configuration

Go to ‘angular.json’ file, it is a configuration schema file.

We changed ‘wwwroot’ folder path in OutputPath.

 

Then enter ng build command in terminal.

 

We can see generated files under wwwroot folder.

 

Configure startup to route to angular application

We have added the following code to configure method in ‘startup.cs’. Here we have setup mvc default rout to index.html that generates under wwwroot folder.

  1. //Redirect non api calls to angular app that will handle routing of the app.    
  2. app.Use(async (context, next) => {  
  3.     await next();  
  4.     if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api/")) {  
  5.         context.Request.Path = "/index.html";  
  6.         await next();  
  7.     }  
  8. });  
  9. // configure the app to serve index.html from /wwwroot folder    
  10. app.UseDefaultFiles();  
  11. app.UseStaticFiles();  
  12. // configure the app for usage as api    
  13. app.UseMvcWithDefaultRoute(); 
Now run project by enter ‘dotnet run’ command in terminal and open ‘localhost:5000’ URL in browser.

 

 
 
 

Setup angular material UI

Install angular material packages and dependencies.

 

Please go through this article to get more details about material components. 

  • ng add @angular/material
  • npm install -d @angular/cdk hammerjs

To use angular material UI components in our Angular contact application, we have created a separate module named ‘app.material.module.ts’ in app folder.

In this module, we imported all dependant material components and we have included in our main app module in this module .

Then, we have imported Angular material theme in the main style.css in src folder

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

 Then, we added this link of material icons into index.html in src folder:

  1. <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">  

Generate contact list & form component

To generate new component, we used ‘ng generate component’ command as below,

 

This we have set up routing for that component in ‘app.routing.ts’.

  1. import {  
  2.     ModuleWithProviders  
  3. } from '@angular/core';  
  4. import {  
  5.     Routes,  
  6.     RouterModule  
  7. } from '@angular/router';  
  8. import {  
  9.     AppComponent  
  10. } from './app.component';  
  11. import {  
  12.     ContactlistComponent  
  13. } from './contactlist/contactlist.component';  
  14. import {  
  15.     ContactformComponent  
  16. } from './contactform/contactform.component';  
  17. const appRoutes: Routes = [{  
  18.     path: '',  
  19.     pathMatch: 'full',  
  20.     component: ContactlistComponent  
  21. }, {  
  22.     path: 'contactform',  
  23.     component: ContactformComponent  
  24. }];  
  25. export const Routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);  

 

Create angular services

To create a consumed contact API that we have created Part 1; we are generating Angular contact services class in app folder using this command:

‘ng generate service contact’

 
  1. import {  
  2.     Injectable  
  3. } from '@angular/core';  
  4. import {  
  5.     HttpClient,  
  6.     HttpParams,  
  7.     HttpErrorResponse  
  8. } from '@angular/common/http';  
  9. import {  
  10.     HttpHeaders  
  11. } from '@angular/common/http';  
  12. import {  
  13.     Observable,  
  14.     throwError  
  15. } from 'rxjs';  
  16. import {  
  17.     catchError  
  18. } from 'rxjs/operators';  
  19. import {  
  20.     IContact  
  21. } from '../model/contact';  
  22. const httpOptions = {  
  23.     headers: new HttpHeaders({  
  24.         'Content-Type''application/json'  
  25.     })  
  26. };  
  27. @Injectable()  
  28. export class ContactService {  
  29.     constructor(private http: HttpClient) {}  
  30.     // get all contact data    
  31.     getAllContact(url: string): Observable < IContact[] > {  
  32.         return this.http.get < IContact[] > (url).pipe(catchError(this.handleError));  
  33.     }  
  34.     // insert new contact details    
  35.     addContact(url: string, contact: IContact): Observable < any > {  
  36.         return this.http.post(url, JSON.stringify(contact), httpOptions).pipe(catchError(this.handleError));  
  37.     }  
  38.     // update contact details    
  39.     updateContact(url: string, id: number, contact: IContact): Observable < any > {  
  40.         const newurl = `${url}?id=${id}`;  
  41.         return this.http.put(newurl, contact, httpOptions).pipe(catchError(this.handleError));  
  42.     }  
  43.     // delete contact information    
  44.     deleteContact(url: string, id: number): Observable < any > {  
  45.         const newurl = `${url}?id=${id}`; // DELETE api/contact?id=42    
  46.         return this.http.delete(newurl, httpOptions).pipe(catchError(this.handleError));  
  47.     }  
  48.     // custom handler    
  49.     private handleError(error: HttpErrorResponse) {  
  50.         if (error.error instanceof ErrorEvent) {  
  51.             // A client-side or network error occurred. Handle it accordingly.    
  52.             console.error('An error occurred:', error.error.message);  
  53.         } else {  
  54.             // the backend returned an unsuccessful response code.    
  55.             // the response body may contain clues as to what went wrong,    
  56.             console.error(`Backend returned code ${error.status}, ` + `body was: ${error.error}`);  
  57.         }  
  58.         // return an observable with a user-facing error message    
  59.         return throwError('Something bad happened; please try again later.');  
  60.     }  
  61. }  

Update main app html template

We have included router outlet place holder to render component based on Angular route.

  1. <!--The content below is only a placeholder and can be replaced.-->  
  2. <mat-toolbar> <span>Contact Application</span> </mat-toolbar>  
  3. <router-outlet></router-outlet>  

 

Update contact form component

In contact form component, we used form group named as 'contactFrm' to bind model with each control and injected dialog data to bind form based on request parameter. 

contactform.component.html 
  1. <form  (ngSubmit)="onSubmit(contactFrm)"  [formGroup]="contactFrm">  
  2.   <h2>{{data.modalTitle}}</h2>  
  3.     
  4.   <div>  
  5.       <mat-form-field appearance="outline">  
  6.       <mat-label>Name</mat-label>  
  7.       <input matInput placeholder="Name" formControlName="name">  
  8.       <!-- <mat-icon matSuffix>sentiment_very_satisfied</mat-icon> -->  
  9.       <!-- <mat-hint>Hint</mat-hint> -->  
  10.       <mat-error *ngIf="formErrors.name">  
  11.         {{ formErrors.name }}  
  12.       </mat-error>  
  13.     </mat-form-field>  
  14.   </div>  
  15.   <div>  
  16.     <mat-form-field appearance="outline">  
  17.       <mat-label>Email</mat-label>  
  18.       <input type="email" matInput placeholder="email" formControlName="email">  
  19.       <mat-error *ngIf="formErrors.email">  
  20.         {{ formErrors.email }}  
  21.       </mat-error>  
  22.     </mat-form-field>  
  23.     
  24.   </div>  
  25.   <p>  
  26.       <mat-radio-group class="contact-radio-group" formControlName="gender" >  
  27.         <mat-radio-button class="contact-radio-button" *ngFor="let gndr of genders" [value]="gndr.id">  
  28.           {{ gndr.name }}  
  29.         </mat-radio-button>  
  30.       </mat-radio-group>  
  31.       <mat-error *ngIf="formErrors.gender">  
  32.         {{ formErrors.gender }}  
  33.       </mat-error>  
  34.   </p>  
  35.   <div>  
  36.     <mat-form-field appearance="outline">  
  37.       <input matInput [matDatepicker]="picker" placeholder="Choose a birthday" formControlName="birth">  
  38.       <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>  
  39.       <mat-datepicker #picker></mat-datepicker>  
  40.       
  41.     <mat-error *ngIf="formErrors.birth ">  
  42.       {{ formErrors.birth }}  
  43.     </mat-error>  
  44.     </mat-form-field>  
  45.   </div>  
  46.   <div>  
  47.     <mat-form-field appearance="outline">  
  48.       <mat-select placeholder="Select a Technology" formControlName="techno">  
  49.         <mat-option>-- None --</mat-option>  
  50.         <mat-option *ngFor="let techno  of technologies" [value]="techno">  
  51.           {{ techno }}  
  52.         </mat-option>  
  53.       </mat-select>  
  54.       <mat-error *ngIf="formErrors.techno ">  
  55.         {{ formErrors.techno }}  
  56.       </mat-error>  
  57.     </mat-form-field>  
  58.   </div>  
  59.   <div>  
  60.     <mat-form-field appearance="outline">  
  61.       <textarea matInput placeholder="Message..." formControlName="message"></textarea>  
  62.       <mat-error *ngIf="formErrors.message ">  
  63.         {{ formErrors.message }}  
  64.       </mat-error>  
  65.     </mat-form-field>  
  66.   </div>  
  67.   <div>  
  68.     
  69.     <button type="button" mat-raised-button color="warn" (click)="dialogRef.close()">Cancel</button>   
  70.     <button type="submit" mat-raised-button color="primary" [disabled]="contactFrm.invalid">{{data.modalBtnTitle}}</button>  
  71.   </div>  
  72.     
  73.   </form>  
To see contactform.component.ts code please refer this GitHub link and final form  looks  as shown in the below screenshot,
 
 
Update contact list component
 
In contact list component, we have used material table to bind contact record using ‘MatTableDataSource’ and called contact service to retrieve data from API. Then we used MatDialog to open contact form component.
 
contactlist.component.html 
  1. <div class="spinner" *ngIf="loadingState; else contactlist">  
  2. <mat-spinner></mat-spinner>  
  3. </div>  
  4. <ng-template class="contactlist" #contactlist>  
  5.   <h2 style="text-align: center;">Contact List</h2>  
  6.   <div class="contactlist-container mat-elevation-z8">  
  7.     <div><button title="Create" mat-raised-button color="accent" (click)="addContact()">Create</button></div>  
  8.     <table mat-table #table [dataSource]="dataSource">  
  9.   
  10.       <!-- Id Column -->  
  11.       <!-- <ng-container matColumnDef="id">  
  12.       <th mat-header-cell *matHeaderCellDef> Id </th>  
  13.       <td mat-cell *matCellDef="let element"> {{element.id}} </td>  
  14.     </ng-container> -->  
  15.   
  16.       <!-- Name Column -->  
  17.       <ng-container matColumnDef="name">  
  18.         <th mat-header-cell *matHeaderCellDef> Name </th>  
  19.         <td mat-cell *matCellDef="let element"> {{element.name}} </td>  
  20.       </ng-container>  
  21.   
  22.       <!-- Email Column -->  
  23.       <ng-container matColumnDef="email">  
  24.         <th mat-header-cell *matHeaderCellDef> Email </th>  
  25.         <td mat-cell *matCellDef="let element"> {{element.email}} </td>  
  26.       </ng-container>  
  27.   
  28.       <!-- Gender Column -->  
  29.       <ng-container matColumnDef="gender">  
  30.         <th mat-header-cell *matHeaderCellDef> Gender </th>  
  31.         <td mat-cell *matCellDef="let element"> {{getGender(element.gender)}} </td>  
  32.       </ng-container>  
  33.   
  34.       <!-- Birth Column -->  
  35.       <ng-container matColumnDef="birth">  
  36.         <th mat-header-cell *matHeaderCellDef> Birthday </th>  
  37.         <td mat-cell *matCellDef="let element"> {{element.birth | date: 'MM-dd-yyyy' }} </td>  
  38.       </ng-container>  
  39.   
  40.       <!-- Technology Column -->  
  41.       <ng-container matColumnDef="techno">  
  42.         <th mat-header-cell *matHeaderCellDef> Technology </th>  
  43.         <td mat-cell *matCellDef="let element"> {{element.techno}} </td>  
  44.       </ng-container>  
  45.   
  46.       <!-- Message Column -->  
  47.       <ng-container matColumnDef="message">  
  48.         <th mat-header-cell *matHeaderCellDef> Message </th>  
  49.         <td mat-cell *matCellDef="let element"> {{element.message}} </td>  
  50.       </ng-container>  
  51.   
  52.       <ng-container matColumnDef="action">  
  53.         <th mat-header-cell *matHeaderCellDef> Action </th>  
  54.         <td mat-cell *matCellDef="let element">  
  55.           <button title="Edit" mat-raised-button color="primary" (click)="editContact(element.id)">Edit</button>  
  56.           <button title="Delete" mat-raised-button color="warn" (click)="deleteContact(element.id)">Delete</button>  
  57.         </td>  
  58.       </ng-container>  
  59.   
  60.       <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>  
  61.       <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>  
  62.     </table>  
  63.   
  64.   </div>  
  65. </ng-template>  
To see contactlist.component.ts code please refer to this GitHub link.

Build components and run the project

Our component is ready. Now build Angular project using 'ng build' command and then run the project by entering 'dotnet run' command in terminal. 
 
 
 
 

Conclusion

This is how we created contact application using ASP.Net Core Web API, Angular 6.0, and Visual Studio code.

You can see the entire code on GitHub and fork it for the starter project.

Please let me know your feedback.