Angular Pagination - Getting Started

NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.

Pagination is a UI component that allows users to navigate through pages and change page size at runtime.

This tutorial explains how to add Pagination to a page and configure the component's core settings. It also covers implementing remote pagination. Colored cards are loaded each time a user switches pages or changes page size. The final result is displayed below:

Each section in this tutorial describes a single configuration step. You can also find the full source code in the following GitHub repository:

View on GitHub

Create Pagination

Add DevExtreme to your Angular application and use the following code to create a Pagination component:

app.component.html
app.component.ts
app.module.ts
  • <dx-pagination></dx-pagination>
  • import { Component } from '@angular/core';
  •  
  • @Component({
  • selector: 'app-root',
  • templateUrl: './app.component.html',
  • styleUrls: ['./app.component.css']
  • })
  • export class AppComponent {
  •  
  • }
  • import { BrowserModule } from '@angular/platform-browser';
  • import { NgModule } from '@angular/core';
  • import { AppComponent } from './app.component';
  •  
  • import { DxPaginationModule } from 'devextreme-angular';
  •  
  • @NgModule({
  • declarations: [
  • AppComponent
  • ],
  • imports: [
  • BrowserModule,
  • DxPaginationModule
  • ],
  • providers: [ ],
  • bootstrap: [AppComponent]
  • })
  • export class AppModule { }

Configure Pagination

This tutorial step guides you through the basic Pagination setup.

Specify the following settings:

  • itemCount sets the total number of items. Pagination does not function properly without this setting.
  • pageIndex sets the initial page to display. This tutorial sets pageIndex to 3 (the default value is 1).
  • allowedPageSizes specifies page sizes available to users. Modify this list as needed. Include 'all' to allow users to display all items on one page. This tutorial uses the default value: [5, 10].
  • pageSize specifies the initial page size.

The following code snippet demonstrates how to apply the aforementioned settings:

app.component.html
app.component.ts
  • <dx-pagination
  • [showInfo]="true"
  • [showNavigationButtons]="true"
  • [itemCount]="total"
  • [pageIndex]="pageIndex"
  • [pageSize]="pageSize"
  • >
  • </dx-pagination>
  • import { Component } from '@angular/core';
  •  
  • @Component({
  • selector: 'app-root',
  • templateUrl: './app.component.html',
  • styleUrls: ['./app.component.css']
  • })
  • export class AppComponent {
  • total = 100;
  • pageIndex = 3;
  • pageSize = 5;
  • }

Implement Remote Pagination

This section explains how to implement remote pagination. Client code generates a color list and requests a remote service for cards representing color entries on the screen. The pagination component helps users browse the resulting color cards.

Implementation can be broken down into three steps:

  1. Generate 100 hex codes.
  2. Fetch color cards from The Color API service when necessary:
    • On page load
    • On page size changes
    • On page index changes
  3. Display color cards obtained from the service.

Implement the first step. Generate 100 random pastel hex codes and add them to an array:

app.component.ts
app.service.ts
  • import { Component } from '@angular/core';
  • import { ColorService } from './app.service';
  •  
  • @Component({
  • selector: 'app-root',
  • templateUrl: './app.component.html',
  • styleUrls: ['./app.component.css'],
  • providers: [ColorService],
  • })
  • export class AppComponent {
  • // ...
  • hexCodes: string[] = [];
  •  
  • constructor(private readonly colorService: ColorService) {}
  •  
  • ngOnInit(): void {
  • this.generateHexCodes();
  • }
  •  
  • generateHexCodes(): void {
  • for (let i = 0; i < this.total; i++) {
  • this.hexCodes.push(this.colorService.getRandomPastelColor());
  • }
  • }
  • }
  • import { Injectable } from '@angular/core';
  •  
  • @Injectable({
  • providedIn: 'root',
  • })
  • export class ColorService {
  • private hsvToHex(h: number, s: number, v: number): string {
  • let r = 0;
  • let g = 0;
  • let b = 0;
  • const i = Math.floor(h / 60);
  • const f = h / 60 - i;
  • const p = v * (1 - s);
  • const q = v * (1 - f * s);
  • const t = v * (1 - (1 - f) * s);
  •  
  • switch (i % 6) {
  • case 0: [r, g, b] = [v, t, p]; break;
  • case 1: [r, g, b] = [q, v, p]; break;
  • case 2: [r, g, b] = [p, v, t]; break;
  • case 3: [r, g, b] = [p, q, v]; break;
  • case 4: [r, g, b] = [t, p, v]; break;
  • case 5: [r, g, b] = [v, p, q]; break;
  • }
  •  
  • const toHex = (x: number): string => Math.round(x * 255).toString(16).padStart(2, '0');
  • return `${toHex(r)}${toHex(g)}${toHex(b)}`;
  • }
  •  
  • getRandomPastelColor(): string {
  • const hue = Math.floor(Math.random() * 360);
  • const saturation = Math.random() * 0.4 + 0.2;
  • const brightness = Math.random() * 0.3 + 0.7;
  • return this.hsvToHex(hue, saturation, brightness);
  • }
  • }

Fetch Data

The following code snippet demonstrates how to fetch data from the Color API:

app.service.ts
  • import { Injectable } from '@angular/core';
  •  
  • @Injectable({
  • providedIn: 'root',
  • })
  • export class ColorService {
  • // ...
  • fetchColorData(hex: string): Observable<Color> {
  • return this.http.get<any>(`${this.apiEndpoint}${hex}`)
  • .pipe(
  • catchError((error: any) => throwError(() => new Error(`Error fetching color: ${error.message || error}`))),
  • )
  • .pipe(map((data: any) => ({
  • name: data.name.value,
  • image: data.image.bare,
  • })));
  • }
  • }

Render Items

The render function determines the subset of cards to be displayed and populates the array with images and alt strings.

app.component.html
app.component.ts
app.service.ts
app.component.css
  • <dx-pagination ... ></dx-pagination>
  • <div id="cards">
  • <ng-container *ngFor="let color of visibleCards">
  • <img [src]="color.image" [alt]="color.name" />
  • </ng-container>
  • </div>
  • import { Component } from '@angular/core';
  • import { firstValueFrom } from 'rxjs';
  • import { ColorService, Color } from './app.service';
  •  
  • @Component({
  • selector: 'app-root',
  • templateUrl: './app.component.html',
  • styleUrls: ['./app.component.css'],
  • providers: [ColorService],
  • })
  • export class AppComponent {
  • // ...
  • colors: Map<string, Color> = new Map();
  • visibleCards: Color[] = [];
  •  
  • constructor(private readonly colorService: ColorService) {}
  •  
  • ngOnInit(): void {
  • // ...
  • void this.fetchColorsForPage();
  • }
  •  
  • async fetchColorsForPage(): Promise<void> {
  • const startIndex = (this.pageIndex - 1) * this.pageSize;
  • const endIndex = this.pageIndex * this.pageSize;
  • const hexSubset = this.hexCodes.slice(startIndex, endIndex);
  •  
  • const promises: Promise<Color>[] = hexSubset.map((hex) => {
  • if (this.colors.has(hex)) {
  • return Promise.resolve(this.colors.get(hex)!);
  • } else {
  • return firstValueFrom(this.colorService.fetchColorData(hex)).then((data) => {
  • const colorData: Color = data;
  • this.colors.set(hex, colorData);
  • return colorData;
  • });
  • }
  • });
  •  
  • try {
  • const fetchedColors = await Promise.all(promises);
  • this.visibleCards = fetchedColors;
  • } catch (error) {
  • console.error('Error fetching colors:', error);
  • }
  • }
  • }
  • // ...
  • export interface Color {
  • image: string;
  • name: string;
  • }
  • #cards {
  • display: flex;
  • justify-content: center;
  • flex-wrap: wrap;
  • }

Handle Page Size and Index Changes

The render function is called on every page index/size change:

app.component.html
app.component.ts
  • <dx-pagination ...
  • (pageIndexChange)="onPageIndexChange($event)"
  • (pageSizeChange)="onPageSizeChange($event)"
  • >
  • </dx-pagination>
  • <!-- ... -->
  • // ...
  • export class AppComponent {
  • // ...
  • onPageIndexChange(val: number): void {
  • this.pageIndex = val;
  • void this.fetchColorsForPage();
  • }
  •  
  • onPageSizeChange(val: number): void {
  • this.pageSize = val;
  • void this.fetchColorsForPage();
  • }
  • }

Integrate LoadPanel

The following code integrate a load panel into the application. The panel appears when the app requests card data from the remote service. This step is optional.

To integrate the DevExtreme LoadPanel component:

  1. Add a LoadPanel to the code.
  2. Display it before calling the render function.
  3. Hide it after render.
app.component.html
app.component.ts
  • <dx-pagination ... ></dx-pagination>
  • <!-- ... -->
  • <dx-load-panel
  • [(visible)]="loadPanelVisible"
  • [showIndicator]="true"
  • [showPane]="true"
  • [hideOnOutsideClick]="false"
  • >
  • <dxo-position my="top" at="top" of="#cards"></dxo-position>
  • </dx-load-panel>
  • // ...
  • export class AppComponent {
  • // ...
  • loadPanelVisible = false;
  •  
  • async fetchColorsForPage(): Promise<void> {
  • const startIndex = (this.pageIndex - 1) * this.pageSize;
  • const endIndex = this.pageIndex * this.pageSize;
  • const hexSubset = this.hexCodes.slice(startIndex, endIndex);
  •  
  • const promises: Promise<Color>[] = hexSubset.map((hex) => {
  • // ...
  • });
  •  
  • this.loadPanelVisible = true;
  • try {
  • const fetchedColors = await Promise.all(promises);
  • this.visibleCards = fetchedColors;
  • } catch (error) {
  • console.error('Error fetching colors:', error);
  • } finally {
  • this.loadPanelVisible = false;
  • }
  • }
  • }