Static Data
Use a simple in-memory array without any server calls. Ideal for prototypes, reference tables, or small datasets that don't need pagination.
The smallest data source
An object with one method, returning of(array). No HTTP, no async, no configuration beyond a height.
Sorting and filtering, without writing either
Click a header or type in the filter row. The data source below sorts nothing and filters nothing — with sortMode and filterApplyMode set to 'client', the grid does both over the rows it already has.
Paging over the same array
The source slices with offset and limit and reports the total. That is the entire implementation — the pager comes from totalCount.
No data source at all
This grid has no [dataSource] binding. It starts empty and every row arrives through grid.applyTransaction() — the shape to use when your data is pushed to you rather than pulled by the grid.
Nothing here yet — press Add a row.
Try adjusting your filters or search criteria.
How it works
The grid's dataSource input expects an object with a fetchRows(params)
method that returns an Observable<{ rows: T[]; totalCount: number }>.
For in-memory arrays, wrapping the result with RxJS of() satisfies that contract
without any async calls.
The grid calls fetchRows() on the initial load, every page change, every sort
change, and every filter change. Your implementation decides how to respond to each
FetchParams:
- Use
p.offsetandp.limitto slice the array for paging. -
Set
sortMode: 'client'in config so the grid sorts the loaded rows in memory — no need to implement sorting infetchRows(). The grid passessorts: []to avoid double-sorting. -
For client-side filtering, inspect
p.filtersmanually. For server-side data sources, serializep.filtersand send to the API — the grid doesn't apply filters itself (unless you implement it infetchRows).
When to use static data
Static in-memory data works well for: configuration tables, reference lists, lookup data,
editable grids where the full dataset fits in memory, and prototyping before the API is ready.
For large server-side datasets, use a real HttpClient-based data source instead
(see Infinite Scroll or Paging).
dataSource is optional
If [dataSource] is omitted entirely, the grid renders with zero rows and shows the
empty state. This is useful when your data arrives via imperative transactions
(grid.applyTransaction()) rather than through a pull-based data source.
With sortMode: 'client' the grid passes sorts: [] to
fetchRows() and sorts the loaded rows itself — your data source only slices
with offset/limit, no sort logic needed.
Data source contract
| Property | Type | Default | Description |
|---|---|---|---|
| dataSource.fetchRows() | (params: FetchParams) => Observable<FetchResult<T>> | — | The only required data-source member — wrap an in-memory array with of() to satisfy it synchronously. |
| params.offset / params.limit | number | — | Slice window for the current page: rows.slice(offset, offset + limit). |
| config.sortMode | 'server' | 'client' | 'server' | client sorts loaded rows in memory — no sort code in fetchRows(). |
| config.scrollMode | 'infinite' | 'paging' | 'virtual-paging' | 'infinite' | This demo uses classic paging with pageSize: 5. |
| FetchResult.totalCount | number | — | Total row count across all pages — drives the pager and scroll length. |