In this article, we are going to implement pagination using angular material in a sample angular(version 12) application.
Create A Sample Angular Application:
Let's create a sample angular project and also install the angular material package.
Install Angular CLI:
npm install -g @angular/cli
npm install -g @angular/cli
Command To Create Angular Application:
ng new your-project-name
ng new your-project-name
Command To Install Angular Material Package:
ng add @angular/material
ng add @angular/material
API:
Here I'm going to use a sample pagination API that I had created. Here I will show the sample response to gain the basic idea over the API.
Create Response Models:
Now let's create models to read the API JSON response.
ng g class models/todo.model
ng g class models/todo.paging.model
ng g class models/todo.paging.model
models/todo.model.ts:
export interface TodoModel { id:number; itemName: string; isCompleted:boolean; }models/todo.paging.model.ts:
import { TodoModel } from "./todo.model"; export interface TodoPagingModel { data: TodoModel[], totalCount:number }
Create A Service Class To Invoke API Endpoint:
Now let's create an angular service class to consume the API endpoint.
ng g service app
app.service.ts:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { TodoPagingModel } from './models/todo.paging.model'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root', }) export class AppService { constructor(private httpClient: HttpClient) {} getTodos(currentPage: number, pageSize: number): Observable<TodoPagingModel> { return this.httpClient.get<TodoPagingModel>( `https://localhost:6001/api/Todo?currentPageNumber=${currentPage}&pagesize=${pageSize}` ); } }
- Here using the 'HttpClient' instance invoking the GET call using 'currentPage' and 'pageSize' as query parameters.
app.module.ts:
import { AppService } from './app.service'; import { HttpClientModule } from '@angular/common/http'; // code hidden for display purpose @NgModule({ imports: [ HttpClientModule ], providers: [AppService] }) export class AppModule {}
Implement Pagination:
Now let's update our 'AppComponent' with our pagination logic.
app.component.html:
<div> <div> <table mat-table [dataSource]="todos"> <ng-container matColumnDef="id"> <th mat-header-cell *matHeaderCellDef>Id</th> <td mat-cell *matCellDef="let row">{{ row.id }}</td> </ng-container> <ng-container matColumnDef="itemName"> <th mat-header-cell *matHeaderCellDef>Item Name</th> <td mat-cell *matCellDef="let row">{{ row.itemName }}</td> </ng-container> <ng-container matColumnDef="isCompleted"> <th mat-header-cell *matHeaderCellDef>Is Completed</th> <td mat-cell *matCellDef="let row">{{ row.isCompleted }}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr> <tr mat-row *matRowDef="let row; columns: columnsToDisplay"></tr> </table> </div> <mat-paginator showFirstLastButtons [pageSizeOptions]="[5, 10, 15]" [length]="totalRecords" [pageSize]='5' > </mat-paginator> </div>
- (Line: 3) The 'dataSource' property needs to assign our data collection that has to be bind to the table.
- Here registered each column of the table with respective columns and cells with the respective data binding property. Each column will be registered uniquely with the help of 'matColumnDef', so its value should be unique.
- (Line: 17) Assigning the variable 'columnsToDisplay' of type array that contains a collection of column names(these names should match with the 'matColumnDef' values). Only columns that are available in the array will be displayed, in spite of we register more columns in the HTML.
- (Line: 21-26) Rendered the 'mat-paginator' component. The directive 'showFirstLastButons' displays the first and last pagination buttons on UI. The 'pageSizeOptions' define the values of the different page sizes that are available in the drop-down selection. The 'length' value is our total number of records at the server. The 'pageSize' value represents the initial page size of the table.
import { Component, ViewChild, AfterViewInit } from '@angular/core'; import { MatPaginator } from '@angular/material/paginator'; import { switchMap, map } from 'rxjs/operators'; import { AppService } from './app.service'; import { TodoModel } from './models/todo.model'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements AfterViewInit { title = 'ang12-paging'; columnsToDisplay = ['id', 'itemName', 'isCompleted']; totalRecords = 0; todos:TodoModel[] = []; @ViewChild(MatPaginator) paginator?:MatPaginator; constructor(private appService:AppService){} ngAfterViewInit(): void { this.pageChange(); this.initialLoad(); } initialLoad(){ let currentPage = (this.paginator?.pageIndex ?? 0)+1; this.appService.getTodos(currentPage, (this.paginator?.pageSize ?? 0)) .subscribe(result => { this.totalRecords = result.totalCount; this.todos = result.data; }) } pageChange(){ this.paginator?.page.pipe( switchMap(() => { let currentPage = (this.paginator?.pageIndex ?? 0)+1; return this.appService.getTodos(currentPage, (this.paginator?.pageSize ?? 0)); }), map( result => { if(!result){ return []; } this.totalRecords = result.totalCount; return result.data; }) ) .subscribe(data => { this.todos = data; }); } }
- (Line: 15) The 'columnsToDisplay' array contains the columns that need to be shown, so with this variable, we can dynamically display our table columns if we need.
- (Line: 16) The 'totalRecords' variable holds the records count at the server, whose value is fetched from the API call.
- (Line: 17) The 'todos' variable of type is a collection of our 'TodoModel'. So the data inside of this variable will be bind to HTML.
- (Line: 19) The 'MatPaginator' holds the reference to the component through with we can listen to the page changes in our component.
- (Line: 23-26) Here we implemented one of the life cycle methods like 'ngAfterViewInit'. Since we mainly depend on 'MatPaginator' child component whose memory will be allocated after HMTL rendering, that is the reason behind using the 'ngAfterViewInit'.
- (Line: 25-35) On angular page loads to make an initial API request this method will be helpful. So for API requests, we need query params like 'currentPage' and 'pageSize' those values available from the 'MatPaginator'. The 'MatPaginator' page index starts from '0', so we need to increment it by '1' and then pass it to the API call.
- (Line: 37-54) Here we register the page change event, so this will get executed on every event raised from the pagination component. The page event will be passed to the 'pipe', then using 'switchMap'(rxjs operator) we returning the new observable that is our API call, which means we are switching from page change event to API call event. After a successful API request, data will be assigned to respective variables.
app.module.ts:
import { MatTableModule } from '@angular/material/table'; import { MatPaginatorModule } from '@angular/material/paginator'; // code hidden for display purpose @NgModule({ imports: [ MatTableModule, MatPaginatorModule ] }) export class AppModule {}Now let's run our application and check the output.
Support Me!
Buy Me A Coffee
PayPal Me
Wrapping Up:
Hopefully, I think this article delivered some useful information on Angular pagination using the Angular Material component. I love to have your feedback, suggestions, and better techniques in the comment section below.
Comments
Post a Comment