DEV Community

javatodev
javatodev

Posted on • Originally published at javatodev.com

Angular Datatable with Pagination Using ag-Grid and REST API

In this article, I’ll explain how we can build a data table with angular using ag-Grid. Additionally, the application will consume third party paginated REST API and load the data to the table.

Here I’m using the API which we developed for our article on, Spring Boot Pagination, Sorting and Filtering.

Final Development Outcome

Alt Text

Technologies I’m going to use in Frontend,

  • Angular 10.1.5
  • ag-Grid
  • Angular HttpClient

Main topics inside the article,

  • Up and Running Backend REST API
  • Developing Angular JS Project
    • Adding ag-Grid into the Initiated Project
    • API Service to Consume REST API
    • Component To Show ag-Grid Implementation
    • Setting Author Name With Custom String Parser
    • Showing Image On ag-Grid
  • Conclusion

Up and Running Backend REST API

Here as I mentioned above, I’ll use the API we have developed in our previous tutorial, First, download the source codes for that Spring boot REST API from here.

$ git clone https://github.com/javatodev/spring-boot-mysql-pagination-filtering-sorting.git
Enter fullscreen mode Exit fullscreen mode

After downloading the project, change the src/main/resources/application.properties to connect with the preferred MySQL instance on your side.

server.port=8081
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/java_to_dev_api_mysql
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
Enter fullscreen mode Exit fullscreen mode

Change these properties accordingly to access the MySQL instance on your machine.

Then start the application using the following command,

$ ./gradlew bootRun
Enter fullscreen mode Exit fullscreen mode

Then you can validate the API status just accessing following URL from your browser or using CURL in the command line,

http://localhost:8081/api/library/book/search?page=0&size=2
Enter fullscreen mode Exit fullscreen mode

It should return an empty list or list of books along with a number of items and number of pages if data is available on your database, after correctly up and running.

I’ve added simple API endpoint to write dummy data set on database.

{
  "bookList": [
    {
      "id": 2,
      "name": "Unlocking Android",
      "isbn": "1933988673",
      "imageUrl": "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/ableson.jpg",
      "author": {
        "id": 3,
        "firstName": "W. Frank",
        "lastName": "Ableson"
      }
    },
    {
      "id": 3,
      "name": "Android in Action, Second Edition",
      "isbn": "1935182722",
      "imageUrl": "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/ableson2.jpg",
      "author": {
        "id": 3,
        "firstName": "W. Frank",
        "lastName": "Ableson"
      }
    }
  ],
  "numberOfItems": 400,
  "numberOfPages": 200
}
Enter fullscreen mode Exit fullscreen mode

If you need more data to test this API, Just trigger following API, then it will create some sample data set in the database. Add an author to the DB before running this API.

curl -X POST http://localhost:8081/api/library/create
Enter fullscreen mode Exit fullscreen mode

Now we have a running API which works correctly.

If you are not familiar with Spring Boot based application then you can use the following Fake REST API from instantwebtools.net which is online and free to use with this tutorial. One thing will be changed since that API returns different data structure but you can set up that with this application as well.

They have this API endpoint which returns the paginated response from their API and it has all the parameters which we need to have in this tutorial.

https://api.instantwebtools.net/v1/passenger?page=0&size=10
Enter fullscreen mode Exit fullscreen mode

Developing Angular JS Project

If you don’t have the basic setup to develop angular JS project, Just follow this documentation to install and configure Angular CLI before starting this tutorial.

Here I’m using angular CLI (10.1.5) to generate our base project for this tutorial.

First, generate your project using the following command and add –routing=true to the same command, then it will generate our base application with all the components which necessary to have in routing enabled angular application.

$ ng new angular-js-datatable-with-spring-boot-api --routing=true
Enter fullscreen mode Exit fullscreen mode

Then select the option you like in the next stages after the above command, For my sources, I’m using the following for the options, But you are free to use any option you would like.

  • Which style sheet format would you like to use? – CSS

Ok, Now we have our fresh angular 10 project with routing module integrations.

Adding ag-Grid into the Initiated Project

$ npm install --save ag-grid-community ag-grid-angular
Enter fullscreen mode Exit fullscreen mode

now all the modules related to ag-grid should be added into the project. Then let’s add the ag-Grid Angular module to our app module (src/app/app.module.ts)

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AgGridModule } from 'ag-grid-angular';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
  declarations: [
    AppComponent,  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    AgGridModule.withComponents([]),
    NgbModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

Additionally, I’m configuring HttpClientModule with this application since It will be used to communicate with the REST API.

After that, add the following CSS imports to src/styles.css or styles.scss get ag-Grid themes,

@import "../node_modules/ag-grid-community/dist/styles/ag-grid.css";
@import "../node_modules/ag-grid-community/dist/styles/ag-theme-alpine.css";
Enter fullscreen mode Exit fullscreen mode

Now we are ready to go with ag-grid implementation.

API Service to Consume REST API

Here we are using a separate service class to communicate with REST API. create a new service using following command.

$ ng g s api
Enter fullscreen mode Exit fullscreen mode

Then add following content into the src/app/api.service.ts Here I’m developing a service method to accept pagesize and pagenumber then retrieve paginated API response from the API using those parameters.

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable({
  providedIn: 'root'
})
export class ApiService {
  constructor(private client: HttpClient) {}
  getAllBooks(pageSize: Number, pageNumber: Number): Observable<any> {
    const url = "http://localhost:8081/api/library/book/search?size="+pageSize+"&page="+pageNumber;
    return this.client.get(url);
  }

}
Enter fullscreen mode Exit fullscreen mode

Component To Show ag-Grid Implementation

In here we are using separate component to build ag-Grid view. So first create a new component and add router param to show it with the root URL.

$ ng g c Dashboard
Enter fullscreen mode Exit fullscreen mode

Then add following into the src/app/app.routing.module.ts in order to setup routes.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';

const routes: Routes = [
 {
   path: "",
   component: DashboardComponent
 }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
Enter fullscreen mode Exit fullscreen mode

Then remove all the content from src/app/app.component.html, and add following,

<router-outlet></router-outlet>
Enter fullscreen mode Exit fullscreen mode

Done now we have implemented a new component with routing, Then we should focus on adding data table component.

First add following into the src/app/dashboard/dashboard.component.ts,

for the moment I’m only going to set two columns in the datatable with name and ISBN from the book API.

so basically you need to set columnDefs with correct field name totally with whatever the data is coming from our API.

Then all the data coming from API will be bound to rowData array and setting rowModelType to ‘infinite’ and default page size will be 10.

onGridReady method will be called when the grid is loaded and it will set the data source with API service and the params will be captured with gridApi.paginationGetPageSize() and gridApi.paginationGetCurrentPage() and its available around whole application for the current session.

After successful retrieval data will be set to the successCallback.

Additionally onPageSizeChanged will be used to set changes on page size.

import { Component, OnInit } from '@angular/core';
import { IDatasource, IGetRowsParams } from 'ag-grid-community';
import { ApiService } from '../api.service';

@Component({
  selector: 'app-new-dashboard',
  templateUrl: './new-dashboard.component.html',
  styleUrls: ['./new-dashboard.component.css']
})
export class NewDashboardComponent implements OnInit {

  private gridApi: any;
  private gridColumnApi: any;  

  constructor(private api: ApiService) { }

  columnDefs = [
    { field: 'name', sortable: true, filter: true , flex: 1, minWidth: 100},
    { field: 'isbn', sortable: true, filter: true , flex: 1, minWidth: 100}
  ];

  rowData = [];
  rowModelType = 'infinite';
  defaultPageSize = 10;

  ngOnInit(): void {
  }

  onGridReady(params: any) {
    this.gridApi = params.api;
    this.gridColumnApi = params.columnApi;
    this.gridApi.setDatasource(this.dataSource);
  }

  dataSource: IDatasource = {
    getRows: (params: IGetRowsParams) => {      
      this.api.getAllBooks(this.gridApi.paginationGetPageSize(), this.gridApi.paginationGetCurrentPage()).subscribe(response => {
        params.successCallback(
          response.bookList, response.numberOfItems
        );
      })
    }
  }

  onPageSizeChanged(event: any) {
    this.gridApi.paginationSetPageSize(Number(event.target.value));
  }

}
Enter fullscreen mode Exit fullscreen mode

Now add following into the src/app/dashboard/dashboard.component.html, this is the UI part for our datatable and there are pending changes that we need to do in the typescript side.

<div style="padding-right:100px;padding-left:100px; padding-top:20px">
    <h1 style="font-weight: bold;">Datatable with Ag-Grid + Angular With Spring Boot REST API</h1>
<div>
    Page Size:
    <select (change)="onPageSizeChanged($event)">
        <option value="10">10</option>
        <option value="100">100</option>
        <option value="500">500</option>
        <option value="1000">1000</option>
    </select>
</div>
<ag-grid-angular 
    #agGrid style="width: 100%; height: 550px;" 
    class="ag-theme-alpine" 
    [rowData]="rowData" 
    id="myGrid"
    [columnDefs]="columnDefs" 
    [pagination]="true" 
    (gridReady)="onGridReady($event)" 
    [rowModelType]="rowModelType"
    [paginationPageSize]="defaultPageSize" 
    [cacheBlockSize]="defaultPageSize" 
    [enableRangeSelection]="true"
>
</ag-grid-angular>
</div>
Enter fullscreen mode Exit fullscreen mode

with ag-grid we need to custom develop page size selection component. That’s why I’ve developed select with onPageSizeChanged method to set selected page size by the user.

Then start the project with following command,

$ ng serve --open
Enter fullscreen mode Exit fullscreen mode

Then following UI should be present when accessing http://localhost:4200 on your browser.

Datatable with Angular Ag-grid and Spring Boot REST API

All done with the basic implementation. let’s add few more changes to show images and custom string columns.

Setting Author Name With Custom String Parser

Here our API is sending author first name and last name in two parameters.

{
      "id": 2,
      "name": "Unlocking Android",
      "isbn": "1933988673",
      "imageUrl": "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/ableson.jpg",
      "author": {
        "id": 3,
        "firstName": "W. Frank",
        "lastName": "Ableson"
      }
    }
Enter fullscreen mode Exit fullscreen mode

So If we need to show both params in a single column in ag-grid, We can use valueGetter and set our custom parser to the getter. Then it will set parsed author name on that column.

Add following method to src/app/dashboard/dashboard.component.ts

nameParser(params:any) {
    if (params.data != null) {
      return params.data.author.firstName+" "+params.data.author.lastName;
    }
    return "";
  }
Enter fullscreen mode Exit fullscreen mode

Then change following column definition on columnDefs,

columnDefs = [
    { field: 'name', sortable: true, filter: true , flex: 1, minWidth: 100},
    { field: 'isbn', sortable: true, filter: true , flex: 1, minWidth: 100},
    { valueGetter: this.nameParser , flex: 1, minWidth: 100, headerName: 'Author'}
  ];
Enter fullscreen mode Exit fullscreen mode

All done, now our datatable could show author name with concatenating first name and last name.

Angular ag-grid with valueGetter to custom colomn implementation

Showing Image On ag-Grid

Now our last column, Image for book. Our API sends the direct URL to the image. So we just needs to set tag with the URL coming from our API.

So to do that we should use custom component and load it with the datatable.

Let’s create another component (src/app/ImageFormatterComponent.ts) with adding the following content.

import { Component } from "@angular/core";

@Component({
  selector: 'app-image-formatter-cell',
  template: `<img border="0" width="50" height="50" src=\"{{ params.value }}\">` })

export class ImageFormatterComponent {
  params: any;
  agInit(params: any){
    this.params = params; 
  } 
}
Enter fullscreen mode Exit fullscreen mode

Here it’s creating a with the value we set from the API.

Then add this same component to the AgGridModule implementation on src/app/app.module.ts

imports: [
    BrowserModule,
    AppRoutingModule,
    AgGridModule.withComponents([ImageFormatterComponent]),
    NgbModule,
    HttpClientModule
  ]
Enter fullscreen mode Exit fullscreen mode

Then call the custom component using cellRendererFramework as below,

columnDefs = [
    { field: 'name', sortable: true, filter: true , flex: 1, minWidth: 100},
    { field: 'isbn', sortable: true, filter: true , flex: 1, minWidth: 100},
    { valueGetter: this.nameParser , flex: 1, minWidth: 100, headerName: 'Author'},
    { field: 'imageUrl' , autoHeight: true, flex: 1, minWidth: 100, headerName: 'Image', cellRendererFramework: ImageFormatterComponent}
  ];
Enter fullscreen mode Exit fullscreen mode

Now our application is almost complete with all the necessary column definitions.

showing images on angular ag grid datatable

All done, Now we have completed the whole implementation with ag-grid on an angular project using REST API.

Conclusion

All done, Now I hope you have a good understanding of how to develop an angular js frontend with datatable using ag-grid and how to configure it to consume paginated REST API developed using Spring Boot. Comment on your ideas or issues you are facing while your development. I’m eagerly waiting to answer those.

You can find source codes for this tutorial from our Github.

Top comments (0)