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.

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. <div>
  4. <mat-form-field appearance="outline">
  5. <mat-label>Name</mat-label>
  6. <input matInput placeholder="Name" formControlName="name">
  7. <!-- <mat-icon matSuffix>sentiment_very_satisfied</mat-icon> -->
  8. <!-- <mat-hint>Hint</mat-hint> -->
  9. <mat-error *ngIf="formErrors.name">
  10. {{ formErrors.name }}
  11. </mat-error>
  12. </mat-form-field>
  13. </div>
  14. <div>
  15. <mat-form-field appearance="outline">
  16. <mat-label>Email</mat-label>
  17. <input type="email" matInput placeholder="email" formControlName="email">
  18. <mat-error *ngIf="formErrors.email">
  19. {{ formErrors.email }}
  20. </mat-error>
  21. </mat-form-field>
  22. </div>
  23. <p>
  24. <mat-radio-group class="contact-radio-group" formControlName="gender" >
  25. <mat-radio-button class="contact-radio-button" *ngFor="let gndr of genders" [value]="gndr.id">
  26. {{ gndr.name }}
  27. </mat-radio-button>
  28. </mat-radio-group>
  29. <mat-error *ngIf="formErrors.gender">
  30. {{ formErrors.gender }}
  31. </mat-error>
  32. </p>
  33. <div>
  34. <mat-form-field appearance="outline">
  35. <input matInput [matDatepicker]="picker" placeholder="Choose a birthday" formControlName="birth">
  36. <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  37. <mat-datepicker #picker></mat-datepicker>
  38. <mat-error *ngIf="formErrors.birth ">
  39. {{ formErrors.birth }}
  40. </mat-error>
  41. </mat-form-field>
  42. </div>
  43. <div>
  44. <mat-form-field appearance="outline">
  45. <mat-select placeholder="Select a Technology" formControlName="techno">
  46. <mat-option>-- None --</mat-option>
  47. <mat-option *ngFor="let techno of technologies" [value]="techno">
  48. {{ techno }}
  49. </mat-option>
  50. </mat-select>
  51. <mat-error *ngIf="formErrors.techno ">
  52. {{ formErrors.techno }}
  53. </mat-error>
  54. </mat-form-field>
  55. </div>
  56. <div>
  57. <mat-form-field appearance="outline">
  58. <textarea matInput placeholder="Message..." formControlName="message"></textarea>
  59. <mat-error *ngIf="formErrors.message ">
  60. {{ formErrors.message }}
  61. </mat-error>
  62. </mat-form-field>
  63. </div>
  64. <div>
  65. <button type="button" mat-raised-button color="warn" (click)="dialogRef.close()">Cancel</button>
  66. <button type="submit" mat-raised-button color="primary" [disabled]="contactFrm.invalid">{{data.modalBtnTitle}}</button>
  67. </div>
  68. </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. <!-- Id Column -->
  10. <!-- <ng-container matColumnDef="id">
  11. <th mat-header-cell *matHeaderCellDef> Id </th>
  12. <td mat-cell *matCellDef="let element"> {{element.id}} </td>
  13. </ng-container> -->
  14. <!-- Name Column -->
  15. <ng-container matColumnDef="name">
  16. <th mat-header-cell *matHeaderCellDef> Name </th>
  17. <td mat-cell *matCellDef="let element"> {{element.name}} </td>
  18. </ng-container>
  19. <!-- Email Column -->
  20. <ng-container matColumnDef="email">
  21. <th mat-header-cell *matHeaderCellDef> Email </th>
  22. <td mat-cell *matCellDef="let element"> {{element.email}} </td>
  23. </ng-container>
  24. <!-- Gender Column -->
  25. <ng-container matColumnDef="gender">
  26. <th mat-header-cell *matHeaderCellDef> Gender </th>
  27. <td mat-cell *matCellDef="let element"> {{getGender(element.gender)}} </td>
  28. </ng-container>
  29. <!-- Birth Column -->
  30. <ng-container matColumnDef="birth">
  31. <th mat-header-cell *matHeaderCellDef> Birthday </th>
  32. <td mat-cell *matCellDef="let element"> {{element.birth | date: 'MM-dd-yyyy' }} </td>
  33. </ng-container>
  34. <!-- Technology Column -->
  35. <ng-container matColumnDef="techno">
  36. <th mat-header-cell *matHeaderCellDef> Technology </th>
  37. <td mat-cell *matCellDef="let element"> {{element.techno}} </td>
  38. </ng-container>
  39. <!-- Message Column -->
  40. <ng-container matColumnDef="message">
  41. <th mat-header-cell *matHeaderCellDef> Message </th>
  42. <td mat-cell *matCellDef="let element"> {{element.message}} </td>
  43. </ng-container>
  44. <ng-container matColumnDef="action">
  45. <th mat-header-cell *matHeaderCellDef> Action </th>
  46. <td mat-cell *matCellDef="let element">
  47. <button title="Edit" mat-raised-button color="primary" (click)="editContact(element.id)">Edit</button>
  48. <button title="Delete" mat-raised-button color="warn" (click)="deleteContact(element.id)">Delete</button>
  49. </td>
  50. </ng-container>
  51. <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  52. <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
  53. </table>
  54. </div>
  55. </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.