Clarity Data Grid: Client‑Side vs Server‑Side Loading
Choose between loading full datasets into the browser or fetching pages from a REST API for Clarity Data Grid, with a concrete Angular implementation and validation steps.
11 Jul 2025, 11:34 UTC

When an Angular application renders a Clarity Data Grid, the first architectural choice is where sorting, filtering, and paging actually happen. Load every row into the browser and interactions feel immediate, but memory use and initial render time climb as the dataset grows. Move that work to a REST API and the browser stays light, yet every click or keystroke may wait on the network. This guide compares the two supported modes, shows how to wire server‑side paging with Angular HttpClient, and lists the checks that catch silent backend mismatches.
Decision constraints
Choose client‑side loading when the dataset is small, relatively static, and the backend does not expose paging endpoints. It requires the least code: bind an array to the grid and let the browser handle the rest.
Choose server‑side loading when rows number in the tens of thousands, when data changes frequently on the server, or when you need to keep the browser payload small. This mode requires a backend that accepts page, size, sort, and filter parameters and returns the matching slice plus a total count.
Comparing supported options
| Aspect | Client‑side | Server‑side |
|---|---|---|
| Data transfer | Full dataset on initial load | One page per request |
| Memory footprint | High; every row stays in the browser | Low; only the current page is held |
| Interaction latency | Instant sorting and filtering | Network round‑trip per action |
| Backend requirements | None beyond a static array | Paging, sorting, and filter query support |
| Implementation effort | Minimal template wiring | API contract plus state management |
Trade‑offs and failure modes
Client‑side grids are simple to build and test, but they degrade badly at scale. A dataset with tens of thousands of rows can consume hundreds of megabytes of browser memory and make the initial render sluggish. Sorting and filtering remain responsive because they run locally, yet the cost is paid up front and repeated every time the page reloads.
Server‑side grids keep the payload small and make large datasets practical, but they introduce two common failure modes. First, if the backend does not use the exact parameter names the grid sends, the request may succeed while returning wrong or empty data. Second, rapid interactions—such as typing in a filter box—can fire many requests in quick succession and overload the API.
Concrete server‑side implementation
Clarity's <clr-datagrid> emits state changes through an event output and accepts a page‑size input. The exact event name and state shape vary slightly across versions, so verify the property names against the Clarity package installed in your project.
Template wiring
<clr-datagrid (clrDgChange)=\"onStateChange($event)\" [clrDgPageSize]=\"pageSize\">
<clr-dg-column>Name</clr-dg-column>
<clr-dg-column>Status</clr-dg-column>
<clr-dg-row *ngFor=\"let row of rows\" [clrDgItem]=\"row\">
<clr-dg-cell>{{ row.name }}</clr-dg-cell>
<clr-dg-cell>{{ row.status }}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]=\"pageSize\"></clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
Component logic with debouncing
The component translates grid state into HTTP query parameters. Because filter typing can produce a stream of events, debounce the state stream before calling the API.
import { Component, OnInit } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
@Component({
selector: 'app-server-grid',
templateUrl: './server-grid.component.html'
})
export class ServerGridComponent implements OnInit {
rows: any[] = [];
total = 0;
pageSize = 25;
loading = true;
private stateChange$ = new Subject<any>();
constructor(private http: HttpClient) {}
ngOnInit(): void {
this.stateChange$.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap(state => this.fetchPage(state))
).subscribe({
next: response => {
this.rows = response.items;
this.total = response.total;
this.loading = false;
},
error: () => {
this.loading = false;
}
});
}
onStateChange(state: any): void {
this.loading = true;
this.stateChange$.next(state);
}
private fetchPage(state: any) {
let params = new HttpParams()
.set('page', String(state.page ? state.page.current : 1))
.set('size', String(state.page ? state.page.size : this.pageSize));
if (state.sort) {
const direction = state.sort.reverse ? 'desc' : 'asc';
params = params.set('sort', `${state.sort.by},${direction}`);
}
if (state.filters) {
state.filters.forEach((filter: any) => {
params = params.set(filter.property, filter.value);
});
}
return this.http.get<any>('/api/records', { params });
}
}
Run the application with ng serve from the workspace root. The component requires no special Angular permissions beyond a standard development server. Replace /api/records with your actual endpoint. The backend must return an object containing at least an items array and a total count so the pagination footer can calculate page numbers.
Validating the switch
- Open Chrome DevTools and select the Network tab.
- Change the page or sort a column. An XHR request should appear with query parameters such as
page,size,sort, and any active filter values. - Open the Sources tab and look for JSON responses. A server‑side grid should never load a single payload containing every row.
- Type quickly in a filter input. The debounce should collapse the keystrokes into a small number of requests rather than one per character.
- Verify that the grid renders the returned rows and that the pagination footer reflects the
totalvalue from the response. - Measure initial load time before and after the switch using the Performance panel or Lighthouse. A server‑side grid should show a smaller initial document transfer and a faster first meaningful paint, though subsequent interactions now include network latency.
Limitations and version notes
Server‑side mode is only as correct as the backend contract. If the API expects sortBy but the grid sends sort, the request may silently return unsorted data. Align parameter names explicitly and test each filter and sort column against the API documentation.
Loading indicators are not optional in server‑side mode. Because each interaction waits on an HTTP response, users need visual feedback that the grid is fetching data. Without it, rapid clicks can appear to do nothing.
The event name and state object properties shown above reflect common Clarity datagrid patterns, but the API surface has evolved across versions. Check the installed @clr/angular package documentation for the exact output binding and state shape before deploying. If the backend cannot support paging, client‑side loading remains the only option without additional infrastructure.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.