Handling Large Datasets in Clarity: Implementing Server-Side Pagination
Learn how to implement server-side pagination with Clarity's Angular Data Grid to handle large datasets without sacrificing browser performance.
21 Oct 2025, 12:33 UTC

The Performance Wall of Client-Side Tables
Loading 5,000 rows into a browser table doesn't just slow down the initial page load; it degrades every single interaction. When you bind a massive array to a data grid, the browser must manage thousands of DOM elements, leading to "janky" scrolling and unresponsive filtering. The solution is server-side pagination: shifting the burden of data slicing from the client's memory to the database.
In the Clarity Design System for Angular, the goal is to create a stateless grid. The UI should not know about the entire dataset; it should only know how many items exist in total and which specific slice is currently visible.
Connecting the Data Grid to the Pagination Component
Clarity separates the table display (clr-datagrid) from the navigation controls (clr-pagination). To make them work together for server-side operations, you must synchronize three key pieces of data: the current page index, the page size, and the total record count.
The clr-pagination component acts as the trigger. Instead of the grid automatically slicing an array, you use the (clrPaginationPageChange) event to notify your backend service that the user has moved to a different page. This event provides the new page number, which you then use to construct your API request (e.g., /api/users?page=2&size=10).
Implementation Example: The Stateless Grid Pattern
This example assumes you are using @clr/angular. The key is to ensure the clr-datagrid is bound to a variable that only holds the current page's results.
<clr-datagrid>
<clr-dg-column>ID</clr-dg-column>
<clr-dg-column>Name</clr-dg-column>
<clr-dg-row *ngFor="let user of users">
<clr-dg-cell>{{user.id}}</clr-dg-cell>
<clr-dg-cell>{{user.name}}</clr-dg-cell>
</clr-dg-row>
</clr-datagrid>
<clr-pagination
[clrPaginationTotalItems]="totalRecords"
[clrPaginationItemsPerPage]="pageSize"
(clrPaginationPageChange)="onPageChange($event)">
</clr-pagination>
// component.ts
export class UserListComponent {
users = [];
totalRecords = 0;
pageSize = 10;
constructor(private userService: UserService) {}
ngOnInit() {
this.loadData(1);
}
onPageChange(page: number) {
this.loadData(page);
}
loadData(page: number) {
// The service handles the HTTP request with page and size params
this.userService.getUsers(page, this.pageSize).subscribe(res => {
this.users = res.data; // Only 10 items
this.totalRecords = res.total; // e.g., 5000
});
}
}
Execution Details
- Run Location: Angular Component template and TypeScript class.
- Permissions: Requires
@clr/angularpackage installed and imported in the module. - Expected Result: The DOM should only contain the number of
clr-dg-rowelements equal topageSize, regardless of thetotalRecordsvalue. - Risk: If
totalRecordsis not updated from the server after a filter is applied, the pagination component may allow users to navigate to empty pages.
Critical Trade-offs and Limitations
While server-side pagination solves memory issues, it introduces new complexities:
- Filter Synchronization: If you implement a search bar, you cannot use client-side filtering. You must send the search term to the server, reset the pagination to page 1, and update the
clrPaginationTotalItemsbased on the filtered result count. - DOM Overhead: Even with pagination, setting a
pageSizethat is too high (e.g., 500+ rows) can cause rendering lag. For datasets requiring massive single-page views, consider virtual scrolling instead of standard pagination. - State Management: Since the grid is stateless, refreshing the page will return the user to page 1 unless you persist the page index in the URL query parameters.
Verifying the Implementation
To confirm your pagination is truly server-side and not just hiding rows, perform these checks:
- Inspect the DOM: Open Browser DevTools. Ensure the number of
<clr-dg-row>elements matches yourpageSize, not your total dataset size. - Network Tab: Click the "Next" button in the pagination component. Verify that a new HTTP request is dispatched with the updated page parameter.
- Boundary Test: Set
totalRecordsto a value slightly higher than your current data (e.g., 11 items with a page size of 10). Ensure the second page loads exactly one row and the "Next" button becomes disabled.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.