Let's get started.
Simple API with Pagination
In this example, we will be using node js to create a simple API with pagination.Here is a simple node application, which response list of users. The users.js file contains an array of data for users with id, name and age. the /users endpoint is already configured for pagination, but without any query, it will response all the data.
Hello Write some things here
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | const express = require('express'); const Users = require('./users.js'); const app = express(); app.use((req,res,next)=>{ res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); app.get('/users', (req,res,next) =>{ console.log("Get Users"); let offset = parseInt(req.query.offset) || 0; let size = parseInt(req.query.limit) || Users.length; let from = offset * size; let to = from + size; let users = Users.slice(from, to); res.status(200).json({ total:Users.length, users }); }); app.listen(3000); console.log("Server Started at http://localhost:3000"); |
You can find the code in this GitHub repo.
Angular Setup
As you are looking for the server-side pagination on the material table, I believe you have all the basic understanding required to set up a table with datasource and paginator. So let not waste any time here. Here is a table with mat paginator
app.component.ts:
app.component.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | import { Component, ViewChild } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { users: any[]; loading: boolean = true; dataSource = new MatTableDataSource<any>(); title = 'pagination'; @ViewChild(MatPaginator) paginator: MatPaginator; constructor(private http: HttpClient) { } ngOnInit() { this.getData(); } getData(){ this.http.get(`http://localhost:3000/users`).subscribe((response: any) =>{ this.loading = false; this.users = response.users; this.dataSource = new MatTableDataSource<any>(this.users); this.dataSource.paginator = this.paginator; }) } } |
app.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <div> <mat-card> <mat-card-header> <mat-card-title> Server Side Pagination in angular </mat-card-title> </mat-card-header> </mat-card> <mat-paginator [pageSizeOptions]="[5, 10, 15, 20, 30]" showFirstLastButtons> </mat-paginator> <div *ngIf="loading;else table"> <mat-spinner class="center"></mat-spinner> </div> <ng-template #table> <table mat-table [dataSource]="dataSource"> <ng-container matColumnDef="id"> <th mat-header-cell *matHeaderCellDef> Id </th> <td mat-cell *matCellDef="let element"> {{element.id}} </td> </ng-container> <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> <tr mat-header-row *matHeaderRowDef="['id', 'name', 'age']"></tr> <tr mat-row *matRowDef="let row; columns: ['id', 'name', 'age'];"></tr> </table> </ng-template> </div> |
With this Setup, we fetch all the users data when the component initialized and use mat-paginator to display with pagination.
![]() |
Mat-Paginator in Table, Angular Material |
Implementing Serverside Pagination with Paginator
Now Let's talk about the API, we had created at the beginning of the article. The /users endpoint accepts two query offset and limit. And in every response, it sends back the total no of data. So that we can understand till when to request got the next data.
Offset is the position in the dataset of a particular record. and the limit is the required data length.
http://localhost:3000/users?offset=1&limit=5
Here offset = 1, so 5 users are already loaded. requesting for next users from index 6 to 10 as limit = 5;
How can we use the mat-paginator to fetch the next data as required? mat paginator docs link.
Going through the documentation we know that it emits an event page When the page is changed. We can make use to that.
First, when the data is loaded we have only 5 users, so the next page is blocked. We can set the length to the total from the server before assigning the data to datasource, in this way the mat paginator behaves like it has all the data. Got it? This is the core of this post.
In simple word
users.length = response.total
This will add a null value for every data that is not available.And in every page event, we make another API call and add the data in the required index. The event provides all the necessary data index, size and previous index.
Here is the final code
app.component.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | import { Component, ViewChild } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { HttpClient, HttpParams } from '@angular/common/http'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { users: any[]; loading: boolean = true; dataSource = new MatTableDataSource<any>(); title = 'pagination'; @ViewChild(MatPaginator) paginator: MatPaginator; constructor(private http: HttpClient) { } ngOnInit() { this.getData('0', '5'); } getData(offset, limit){ let params = new HttpParams(); params = params.set('offset', offset); params = params.set('limit', limit); this.http.get('http://localhost:3000/users?' + params.toString()) .subscribe((response: any) =>{ this.loading = false; this.users = response.users; this.users.length = response.total; this.dataSource = new MatTableDataSource<any>(this.users); this.dataSource.paginator = this.paginator; }) } getNextData(currentSize, offset, limit){ let params = new HttpParams(); params = params.set('offset', offset); params = params.set('limit', limit); this.http.get('http://localhost:3000/users?' + params.toString()) .subscribe((response: any) =>{ this.loading = false; this.users.length = currentSize; this.users.push(...response.users); this.users.length = response.total; this.dataSource = new MatTableDataSource<any>(this.users); this.dataSource._updateChangeSubscription(); this.dataSource.paginator = this.paginator; }) } pageChanged(event){ this.loading = true; let pageIndex = event.pageIndex; let pageSize = event.pageSize; let previousIndex = event.previousPageIndex; let previousSize = pageSize * pageIndex; this.getNextData(previousSize, (pageIndex).toString(), pageSize.toString()); } } |
getNextData(currentSize, offset, limit) is the methods you are interested in. As we had already set the length to total, pushing additional data will add it after the index (living those null value in the middle) so we should set back the size to currentSize and push data and set its size to the total.
![]() |
Mat-Paginator with server side pagination, Data Table Angular |
You can find the source code in this GitHub repo.
That's all. You implement server-side pagination with material paginator in the material data table.
Angular Material Data Table Paginator with Server Side Pagination
Reviewed by Blogger Nepal
on
April 01, 2020
Rating:

Great artical
ReplyDeleteThanks for the comment. :)
DeleteThank you mate.. you saved my lot of efforts.
ReplyDelete