Weekly Webtips
Published in

Weekly Webtips

Tech: Building Reusable Server-side Pagination for Ag-grid in Angular

Server-side Pagination Starter Kits

When it comes to picking the best grid components for UI, ag-grid will always be an indisputable pick by many developers. The fact that this library provides us the ability to customize its component and never disappoints us with its performance makes it one of the best component libraries out there. However, the free version of the library does not support server-side pagination out of the box which turns away large and medium app developers from using the library. Today we will learn how to build server-side pagination that works with ag-grid and Angular and how it can be reused across the app.

Prerequisites

  • Angular
  • ag-grid (Free version)

Implementation

The key secret about building server-side pagination for your grid is to provide your own implementation of datasource. Datasource is basically a callback method that is triggered whenever there are changes in the page number, page size, sorting, and filtering. We then encapsulate this logic inside an Angular directive in order to reuse the codes.

Grid APIs

First, we need to define some basic APIs below

// remote-grid-api.tsimport { GridApi, IGetRowsParams } from 'ag-grid-community';
import { Observable } from 'rxjs';
export interface RemoteGridApi {
getData: (params: IGetRowsParams)
=> Observable<{ data; totalRecords }>;

getDataError?: (err) => void;
gridApi: GridApi;
}
  • getData: a callback method that handles remote data retrieval. This callback should provide several query parameters (page, pageNum, sort, etc.) and return an observable of data. Note that the returned observable must contain two items: the list of paginated data and the total records in the remote database.
  • getDataError: a callback method that handles exceptions when retrieving remote data.
  • gridApi: ag-grid’s APIs.

Anguar Directive

Next, we need to build a custom directive to implement our datasource. Our directive is called RemoteGridBindingDirective. It accepts an instance of RemoteGridApi as an input.

// remote-grid-binding.directive.tsimport { Directive, EventEmitter, HostListener, Input, Output} from '@angular/core';
import { GridApi, IDatasource, IGetRowsParams } from 'ag-grid-community';
import { EMPTY } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { RemoteGridApi } from './remote-grid-api';
@Directive({
selector: '[remoteGridBinding]'
})
export class RemoteGridBindingDirective { @Input()
remoteGridBinding: RemoteGridApi;


@Output()
remoteGridReady = new EventEmitter();
constructor() {} @HostListener('gridReady', ['$event'])
gridReady(gridApi: GridApi) {
gridApi.api.setDatasource(this.dataSource);
this.remoteGridReady.emit(gridApi);
}

handleError(err) {
...
}

dataSource: IDatasource = {
...
};
}

This directive will be attached to the ag-grid component to listen to the gridReady event. When gridEvent event gets triggered, the callback will provide us with gridApi object which we can use to set our custom datasource. After that, gridApi object will be emitted to the parent component.

See below for the implementation of datasource.

dataSource: IDatasource = {
getRows: (params: IGetRowsParams) => {
this.remoteGridBinding
.getData(params)
.pipe(
tap(({ data, totalRecords }) =>
params.successCallback(data, totalRecords)
),
catchError(err => this.handleError(err))
)
.subscribe();
}
};

Our dataSouce object must implement getRows() function. This function should call getData() API from RemoteGridApi and handle success or error callbacks. Remember to pass the data list and total records as parameters in the success callback to update the grid.

Grid Container

The final step is to integrate the angular directive we declared previously to ag-grid component. Note that this component must implement RemoteGridApi in order to comply with our remote grid directive.

// grid-container.component.tsimport { Component } from '@angular/core';
import { GridApi } from 'ag-grid-community';
import { Observable, of } from 'rxjs';
import { RemoteGridApi } from './remote-grid-api';
@Component({
selector: 'grid-container',
templateUrl: './grid-container.component.html'
})
export class AppComponent implements RemoteGridApi {
columnDefs = [
{ field: 'make' },
{ field: 'model' },
{ field: 'price' }
];
gridOptions = {
pagination: true,
rowModelType: 'infinite',
cacheBlockSize: [number],
paginationPageSize: [number]
};

gridApi: GridApi;
remoteGridBinding = this;

onGridReady(params) {
this.gridApi = params.api;
}
getData(params): Observable<{ data; totalRecords }> {
return of(
{
data: [list of data],
totalRecords: [total number]});
}
}

In this component we need to accomplish four things:

  • Update the gridOptions’ rowModelType to ‘infinite’ and declare cacheBlockSize and paginationPageSize for your grid.
  • Set the instance of this component to remoteGridBinding.
  • Implement getData() API.
  • Implement onGridReady() callback (optional).

This is the html template for our grid component. The component should apply the remoteGridBinding directive with the instance of RemoteGridApi.

// grid-container.component.html<ag-grid-angular 
[columnDefs]="columnDefs"
[remoteGridBinding]="remoteGridBinding"
[gridOptions]="gridOptions
(remoteGridReady)="onGridReady($event)">
</ag-grid-angular>

See full demo here.

Conclusion

I hope this article will provide you some basic steps to get started with building server-side pagination with ag-grid. Feel free to post any questions in the comment below. Cheers!

--

--

--

Explore the world of web technologies through a series of tutorials

Recommended from Medium

Next-Redux-Wrapper Tutorial. How It Works and How To Configure It Properly.

Next.js + Redux with next-redux-wrapper

JS Comparisons

8 Miraculous Ways to Bolster Your React Apps

Deploy your Docz site with Heroku

Build a Command Line Interface (CLI) Application with Node.js

First CLI App using Node JS for Beginner’s

How to Use React and Chart.js

Development step 4: Create a Minimal Weather App

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Khoi Bui

Khoi Bui

Front End architect, opensource contributor and investment enthusiast. New content posted every week.

More from Medium

Angular vs. React: Which Would Be a Better Solution in 2022?

Angular vs React.js in Enterprise Level Application

React to Angular: Use Redux for State Management in Angular with TypeScript

Stop using ANY in typescript