Create Angular Project and Communicate with .Net Core

  1. How to setup VS Code environment for ASP.NET Core Project
  2. Use code first to connect database in .Net Core API
  3. Use the Repository pattern in .Net core
  4. Create .Net Core Api controller for CRUD with repository
  5. Use the Serilog in .Net Core
  6. Create Angular Project and Communicate with .Net Core
  7. Create Paging Data from .Net Core Api
  8. How to do Unit Testing for the Core Api Project with Repository

We have created the ASP.NET Core Api project, the Api only for backend data handler, now we need to create the client side project to call the Api and present the website layout for end user. Here I will use Angular for client side project.

1. Why Angular

There are some of key advantages of using Angular

Do you want to be a good trading in cTrader?   >> TRY IT! <<

Component architecture – Angular promotes building applications using components. This makes the code modular, reusable and maintainable.
Declarative templates – The templates in Angular use HTML to define the UI layout declaratively. This makes it easier to visualize the UI.
Data binding – Angular handles data binding automatically between components, their templates and the application data. This reduces boilerplate code.
TypeScript support – Angular uses TypeScript which brings static typing to JavaScript. This improves code quality and maintainability.
Dependency injection – Angular comes with a built-in dependency injector that makes the code loosely coupled and easy to test.
Testing – Angular was designed with testing in mind. It has great unit and end-to-end testing support.
Cross platform – Angular can be used to build web, mobile and desktop applications from the same codebase.
Community and Google support – Angular is actively developed and maintained by Google. It also has a large community.
A lot of 3rd party extensions – There are a lot of 3rd party extensions support, this can save many of times for help us to create the project.
Features – Angular ships with a lot of built-in features like routing, forms handling, HTTP services, etc. This reduces boilerplate code.
Stable releases – The Angular team focuses on stability and quality with planned major releases every 6 months.

So, Angular simplifies web development by providing a robust framework to build declarative, component-based applications. With its strong features, community support and Google backing, it is a reliable choice for building modern web applications.

2. Create Angular Project

2.1 Install Angular

If you are first time for using Angular, you need to install the CLI, you can execute below command in VS Code terminal as below

npm install -g @angular/cli

Base on our previous Api project, so we goto Demo folder in VS Code terminal and execute below command for creating a new Angular project

ng new MyDemo.Client

After that, the folder structure should be like below

size300

2.2 Running the project

We can try to run the Angular project first, for easy debug, I will suggest using the HMR for running it, the HMR means Hot Module Replacement, which is a development feature that allows you to update the code of your running application without having to reload the entire page. This can greatly speed up the development process by allowing you to see changes in your code immediately, without having to wait for the application to rebuild and reload.

In Angular, you can enable HMR by using the ng serve command with the –hmr flag, like this:

ng serve --hmr

but for convenient to use, we can add the below command to /MyDemo.Client/package.json file under scripts section

"scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "hmr": "ng serve --hmr --disable-host-check --port 4810"
  },

and you can run the command as below for start the project

npm run hmr

after that, you will find there is an Url in console, and the port that’s what you set in the package.json

and you can press Ctrl + C for terminating.

3. Create an user page

3.1. Create user component

For this sample, we just need to create an user page for demonstrate how to do get data from .Net Core Api. Use the below command for create an user-management component

ng generate component user-management

it will generate 4 files in an user-management folder

user-management.component.html : the html layout for displaying
user-management.component.scss : cause we use the scss for handle the style when we create the project, so it will auto generate the scss style sheet file
user-management.component.spect.ts : the unit test file for testing the component
user-management.component.ts : you can think that’s the code-behind file for handle the business logic with typescript

by the way, if you don’t want to generate so many files (actually the unit test file should be use for a few times), you can also use the command for control it, for example the below command will skip the test and style file

ng generate component user-management  --skip-tests --inline-style 

and for easier to use, you also can use below command for the same result

ng g c user-management  --skip-tests --inline-style 

3.2 Update the routing

Update the /src/app/app-routing.module.ts, add the user management route, so that we can access from the url

const routes: Routes = [
  { path: 'user-management', component: UserManagementComponent },
];

Cause we just want a simple page for demo, so update the app.component.html , remove other html and just keep the style and base structure, put the router outlet to the main content, so we can remove all of the html code after <h2>Resources</h2> and the result should be like below

3.3 About the router-outlet:

The router-outlet directive is used to display the components that correspond to the current route. When a route is activated, the component that corresponds to that route is displayed within the router-outlet tag.

It’s typically included in the root component of your application, such as app.component.html. When a user navigates to a route in your application, Angular will dynamically replace the contents of the router-outlet tag with the component that corresponds to that route.

So in our case, it will show the user management component’s content, after that, you will see the below result

4. Create the page layout

4.1.1 Create the models

As we need to show the user data from Api, so we also need to create a same user model in client side map to Api. Create models folder under app folder, and create the user.ts model. We can use interface for the model in angular:

//MyDemo.Client/src/app/models/user.ts

/**
 * ~ User model for mapping to Api
 */
export interface User {
  id?: number;
  isActive?: boolean;
  isDeleted?: boolean;
  name?: string;
  password?: string;
  email?: string;
  createdAt?: Date;
  updatedAt?: Date;
}

and we also need to handle the Api result, so should be there is a same model for mapping

//MyDemo.Client/src/app/models/api-result.ts

/**
 * ~ The common API result model
 */
export interface ApiResult<T> {
  data?: T;
  success: boolean;
  message: string;
}

in the end, we want to show data in a table list layout (grid), so it’s need to support some paging values, we can create a model like below

//MyDemo.Client/src/app/models/data-list-result.ts

/**
 * ~The common data list result model
 */
export interface DataListResult<T> {
  data: T[];
  pageIndex: number;
  pageSize: number;
  totalCount: number;
  totalPages: number;
  sortColumn: string;
  sortOrder: string;
  filterColumn: string;
  filterQuery: string;
}

the data will be a dynamic object, so we use the generic type.

4.2. Use the extensions (or packages)

One of the advantage it there are a lot of great extensions for Angular, so we can use them to easy to create a pretty layout! For this sample, I will use @ng-matero/extensions for create the grid layout, run below command for install it

npm install @ng-matero/extensions --save

For using ng-matero/extensions, we need to add the module to app.module.ts, and because this module base on angular material, so we also need to add some material modules

//MyDemo.Client/src/app/app.module.ts

//import the base form and material modules
import { FormsModule } from '@angular/forms';

import { MatFormFieldModule } from '@angular/material/form-field';
import { MatButtonModule } from '@angular/material/button';
import { MatInputModule} from '@angular/material/input';
import {TextFieldModule} from '@angular/cdk/text-field';

//import the grid module
import { MtxGridModule } from '@ng-matero/extensions/grid';

and set these modules into imports in @NgModule

@NgModule({
  declarations: [
    AppComponent,
    UserManagementComponent
  ],
  imports: [
    FormsModule,
    MatInputModule,
    MatButtonModule,
    TextFieldModule,
    MatFormFieldModule,
    MtxGridModule,
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

4.3. Create the user management page

4.3.1. Frontend layout

if you used the angular CLI to create the user management component, it will auto add the reference in your app.module, but we still need to set the app routing for user management

//MyDemo.Client/src/app/app-routing.module.ts

const routes: Routes = [
  { path: 'user-management', component: UserManagementComponent },
];

after that, we can use the url http://localhost:4801/user-management to access.

Ok, let’s update the user management page layout. We will use the material theme for the layout and ng-matero/extensions grid for showing data, so the frontend html codes should be like below

<!-- user-management.component.html -->

<h1>User Management </h1>

<div class="row">
  <div class="col-sm-12">
      <!-- use the material form field and button -->
      <mat-form-field class="col-sm-3">
        <input matInput [(ngModel)]="query.q" name="q" (keyup.enter)="search()" placeholder="Filter by user name">
      </mat-form-field>
      <button class="m-r-8 bg-green-700 text-light" mat-raised-button  (click)="search()">Search</button>
      <button class="m-r-8 bg-red-700 text-light" mat-raised-button (click)="reset()">Reset</button>
  </div>
</div>
<p></p>

<!-- use the ng-matero grid -->
<mtx-grid [data]="list"
          [columns]="columns"
          [length]="total"
          [loading]="isLoading"
          [hideRowSelectionCheckbox]="false"
          [multiSelectable]="true"
          [rowSelectable]="true"
          [columnResizable]="true"
          [columnSortable] = "true"
          [pageOnFront]="false"
          [toolbarTitle]="'Show Columns'"
          [showToolbar]="true"
          [rowHover]="true"
          [rowStriped]="true"
          [pageIndex]="query.page"
          [pageSize]="query.per_page"
          [pageSizeOptions]="[5,10,20]"
          (page)="getNextPage(event)"
          (sortChange)="sortingChange(event)"
          [sortOnFront] = "false">
</mtx-grid>

you can goto here for the details how to use the grid.

4.3.2. Backend grid

We also need to update the backend ts file

//user-management.component.ts

//import the grid and material paginator, we need to support paging
import { PageEvent } from '@angular/material/paginator';
import { MtxGridColumn } from '@ng-matero/extensions/grid';

define the variable for paging default values

public defaultFilterColumn: string = "name";
public defaultPageIndex: number = 0;
public defaultPageSize: number = 10;
public defaultSortColumn: string = "name";
public defaultSortOrder: "asc" | "desc" = "asc";
public isLoading = true;
public list: any[] = []; //model listing data
public total = 0;   //the total records
public filterQuery?: string; //filter query for search 

define the grid’s column, it will be apply to frontend html value

public columns: MtxGridColumn[] = [ 
  { header: 'Id', field: 'id', hide: true },
  { header: 'Active', field: 'isActive', sortable: true,
      type: 'tag',
      tag: {
        true: { text: 'Yes', color: 'red-100' },
        false: { text: 'No', color: 'green-100' },
      },
  },
  { header: 'User Name', field: 'name', sortable: true, minWidth: 250 },
  { header: 'Email', field: 'email', minWidth: 250 ,sortable: true },
  { header: 'Created Date', field: 'createdAt' , minWidth: 150, sortable: true},
  { header: 'Updated Date', field: 'updatedAt' , minWidth: 160, sortable: true},
];

you can see the column field name should be same with the user model’s field name.

4.3.3. Create service

For support get data from Api, we can create a service for handle it. Create a services folder and user-management.service.ts as below

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { debounceTime, Observable, tap } from 'rxjs';
import { DataListResult } from '../models/data-list-result';
import { ApiResult } from '../models/api-result';
import { User } from '../models/user';

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

  constructor(public http: HttpClient) { }

  public getData(
    pageIndex: number,
    pageSize: number,
    sortColumn: string,
    sortOrder: string,
    filterColumn: string | null,
    filterQuery: string | null
  ): Observable<ApiResult<DataListResult<User>>> {
    var url = "http://localhost:5293/api/UserManagement/users";

    //pass the params to api for get data
    var params = new HttpParams()
      .set("pageIndex", pageIndex.toString())
      .set("pageSize", pageSize.toString())
      .set("sortColumn", sortColumn)
      .set("sortOrder", sortOrder);
    if (filterColumn && filterQuery) {
      params = params
        .set("filterColumn", filterColumn)
        .set("filterQuery", filterQuery);
    }

    //call the api and return the result map to DataListResult and User model
    return this.http.get<ApiResult<DataListResult<User>>>(url, { params });
  }
}

As you can see, we need to pass many parameters to Api for support paging, and the Api should return the DataListResult<T> object. But for the previous article, our user Api didn’t support these parameters, don’t worry, we will update the Api later, for now , let’s complete the user-management.component.ts first!

4.3.4. Handle get data and filter methods

For using the user service, we need to pass it into constructor, so update the user-management.component.ts as below

constructor(private userManagementService: UserManagementService,
      private dialog: MtxDialog) { }

and also use the MtxDialog for showing error messages.

Next, we need to define a query object for save the filter and paging data

public query = {
  q: '',
  sort: 'name',
  order: 'desc',
  page: 0,
  per_page: this.defaultPageSize,
};

and then, we can create a getData call the service method

public getData() {
  //get sort column
  var sortColumn = (this.query.sort)
    ? this.query.sort
    : this.defaultSortColumn;
  //get the order method
  var order = (this.query.order)
    ? this.query.order
    : this.defaultSortOrder;
  //get the filter query
  var filterQuery = (this.query.q)
    ? this.query.q
    : null;
  //call service to get data from Api
  this.userManagementService.getData(
    this.query.page,
    this.query.per_page,
    sortColumn,
    order,
    this.defaultFilterColumn,
    filterQuery).subscribe(res => {
        //console.log('res', res);
        if(res.success){
          this.list = res.data ? res.data.data : [] ;
          this.total = res.data? res.data.totalCount : 0;
        } else {
          this.dialog.alert(`Failed to get data!`);
        }
      }
    );
}

after that, we can handle the search and paging methods

public search() {
  this.query.page = 0;
  this.getData();
}
public reset() {
  this.query.q = '';
  this.query.page = 0;
  this.getData();
}
//goto next page event
public getNextPage(e: PageEvent) {
  this.query.page = e.pageIndex;
  this.query.per_page = e.pageSize;
  this.getData();
}
//sorting change event
public sortingChange(e: Sort) {
    //console.log('sortingChange', e);
    this.query.sort = e.active;
    this.query.order = e.direction;
    this.getData();
}
//for load data when first time access the page
public loadData(query?: string) {
  var pageEvent = new PageEvent();
  pageEvent.pageIndex = this.defaultPageIndex;
  pageEvent.pageSize = this.defaultPageSize;
  this.filterQuery = query;
  this.getData();
}
//load data when access the page
public ngOnInit() {
  this.loadData();
}

So far, we finished the client side codes, we can just take a look the page

Ok, I know, there is a last important thing we still need to do, otherwise we can’t get any data from our Api. But because there are also many things need to do, so I will describe the details in the next article 🙂

Loading

Views: 47
Total Views: 430 ,

One thought on “Create Angular Project and Communicate with .Net Core

Leave a Reply

Your email address will not be published. Required fields are marked *