Server-side row model
The server-side model requests block-aligned row slices as the viewport or page needs them. Filtering, sorting, grouping, and full-data aggregation are sent to the data source instead of calculated over an incomplete browser cache.
- React
- Angular
- Core TypeScript
const dataSource: IServerSideDataSource = {
async getRows({ request }) {
const response = await fetch("/api/orders", {
method: "POST",
body: JSON.stringify(request),
});
return response.json(); // { rows, totalRows }
},
};
<Grid rowModelType="serverSide" serverSideDataSource={dataSource} />
dataSource: IServerSideDataSource = {
getRows: async ({ request }) => {
const response = await fetch("/api/orders", {
method: "POST",
body: JSON.stringify(request),
});
return response.json();
},
};
<awb-grid
rowModelType="serverSide"
[serverSideDataSource]="dataSource"
/>
const core = new GridCore(measurer, {
rowModelType: "serverSide",
serverSideBlockSize: 100,
serverSideDataSource: {
async getRows({ request }) {
return fetchOrders(request); // { rows, totalRows }
},
},
});
await api.refreshServerSideData({ purge: false });
Request contract
getRows({ request }) receives startRow, endRow, active filters, ordered
sorts, groupBy, the current groupKeys path, and requested aggregates.
Return { rows, totalRows }; root responses may also provide columns and a
schemaVersion for server-driven schemas.
import type { IServerSideDataSource } from "@agility-workbench/grid";
const serverSideDataSource: IServerSideDataSource = {
async getRows({ request }) {
const response = await fetch("/api/orders", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(request),
});
return response.json(); // { rows, totalRows }
},
};
const options = {
rowModelType: "serverSide",
serverSideBlockSize: 100,
serverSideDataSource,
} satisfies GridOptions;
Server-provided schema
const serverSideDataSource: IServerSideDataSource = {
async getRows({ request }) {
return {
rows: await loadRows(request),
totalRows: 500,
schemaVersion: "orders-v2",
columns: [
{ key: "orderNo", label: "Order" },
{ key: "total", label: "Total", type: ColumnType.CURRENCY },
],
};
},
};
A server-driven schema applies only while the application has not supplied
column definitions itself — through columnDefs at creation, a wrapper prop,
updateGridOptions({ columnDefs }), or api.setColumnDefs. Application
definitions always win; release them with
updateGridOptions({ columnDefs: undefined }) to let the server's schema apply
again. An unchanged schema is deduped by schemaVersion (or by structural
signature when no version is sent), so resending it with every block is cheap.
Omitting totalRows creates an open-ended listing. The grid probes forward
until a short block establishes the end and displays provisional pagination
totals with a + suffix.
Refresh server data
await api.refreshServerSideData();
await api.refreshServerSideData({ purge: true });
await api.refreshServerSideData({ groupKeys: ["EMEA"], purge: false });
Use a soft refresh to keep visible rows while refetching, or { purge: true }
to discard affected blocks immediately. A groupKeys path limits refresh to
one subtree.
For server-side pagination with expensive counts, pair an open-ended listing with a hint:
const options = {
rowModelType: "serverSide",
pagination: true,
pageSize: 50,
paginationUnknownTotalTooltip: "The server is still discovering the total",
serverSideDataSource,
} satisfies GridOptions;