@reforgium/data-grid 3.2.2 → 3.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +101 -1
- package/README.md +198 -168
- package/fesm2022/{reforgium-data-grid-grid-overlay-scroll.feature-CaO2mnI-.mjs → reforgium-data-grid-grid-overlay-scroll.feature-BuyObmQ7.mjs} +41 -6
- package/fesm2022/reforgium-data-grid-paginator.mjs +69 -32
- package/fesm2022/{reforgium-data-grid-reforgium-data-grid-MQb2oHWO.mjs → reforgium-data-grid-reforgium-data-grid-BP7MSHYb.mjs} +549 -107
- package/fesm2022/reforgium-data-grid-ui.mjs +2 -2
- package/fesm2022/reforgium-data-grid.mjs +1 -1
- package/package.json +2 -3
- package/types/reforgium-data-grid-paginator.d.ts +3 -1
- package/types/reforgium-data-grid.d.ts +160 -26
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@reforgium/data-grid)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
**High-performance data grid for Angular
|
|
6
|
+
**High-performance data grid for Angular 18+.**
|
|
7
7
|
|
|
8
|
-
`@reforgium/data-grid` provides a flexible and performant component for displaying large tabular datasets.
|
|
8
|
+
`@reforgium/data-grid` provides a flexible and performant component for displaying large tabular datasets.
|
|
9
9
|
It focuses on smooth scrolling, predictable layout, and full control over rendering via templates and signals.
|
|
10
10
|
|
|
11
11
|
Designed for **real-world datasets**, not demo tables.
|
|
@@ -19,19 +19,24 @@ Designed for **real-world datasets**, not demo tables.
|
|
|
19
19
|
- Infinity scroll (loads data when reaching the bottom)
|
|
20
20
|
- Jitter-free fixed (sticky) columns
|
|
21
21
|
- Two-line text clamp (header + body) with ellipsis
|
|
22
|
-
- Declarative column DSL (`<re-dg-column>`)
|
|
22
|
+
- Declarative column DSL (`<re-dg-column>`) _[NEW in 2.0.0]_
|
|
23
23
|
- Column expanders (hidden columns via toggler)
|
|
24
24
|
- Scrollable overlay scrollbar
|
|
25
25
|
- Pinned rows (top and bottom)
|
|
26
26
|
- Custom templates for headers, cells, pinned rows, icons
|
|
27
|
-
- Skeleton loading rows for pagination/infinity
|
|
27
|
+
- Skeleton loading rows for pagination/infinity _[NEW in 2.0.0]_
|
|
28
28
|
- Row selection (single / multi)
|
|
29
29
|
- Signals-based API (`signal()` first)
|
|
30
|
-
- Paginator component
|
|
31
|
-
- Column manager dropdown
|
|
30
|
+
- Paginator component _[NEW in 1.1.0]_
|
|
31
|
+
- Column manager dropdown _[NEW in 2.0.0]_
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
35
|
+
## Requirements
|
|
36
|
+
|
|
37
|
+
- Angular >=18.0.0
|
|
38
|
+
- RxJS is not required by this package.
|
|
39
|
+
|
|
35
40
|
## Installation
|
|
36
41
|
|
|
37
42
|
```bash
|
|
@@ -44,12 +49,10 @@ import { DataGridPaginator } from '@reforgium/data-grid/paginator';
|
|
|
44
49
|
import { DataGridColumnManager } from '@reforgium/data-grid/column-manager';
|
|
45
50
|
|
|
46
51
|
@Component({ imports: [DataGrid, DataGridPaginator] })
|
|
47
|
-
export class SomeComponent {
|
|
48
|
-
}
|
|
52
|
+
export class SomeComponent {}
|
|
49
53
|
```
|
|
50
54
|
|
|
51
55
|
```html
|
|
52
|
-
|
|
53
56
|
<re-data-grid
|
|
54
57
|
mode="infinity"
|
|
55
58
|
[data]="users"
|
|
@@ -73,12 +76,7 @@ declare const usersSource: GridPagedDataSource<User>;
|
|
|
73
76
|
```
|
|
74
77
|
|
|
75
78
|
```html
|
|
76
|
-
<re-data-grid
|
|
77
|
-
mode="infinity"
|
|
78
|
-
[source]="usersSource"
|
|
79
|
-
[columns]="columns"
|
|
80
|
-
[pageSize]="20"
|
|
81
|
-
/>
|
|
79
|
+
<re-data-grid mode="infinity" [source]="usersSource" [columns]="columns" [pageSize]="20" />
|
|
82
80
|
```
|
|
83
81
|
|
|
84
82
|
In `source` mode, the grid keeps its own internal page buffer for infinity scrolling, so the parent does not need to maintain one ever-growing accumulated `data[]`.
|
|
@@ -87,14 +85,20 @@ Important:
|
|
|
87
85
|
|
|
88
86
|
- The grid does not auto-fetch on mount in `source` mode.
|
|
89
87
|
- The parent should first apply filters / route params / query state and then call the source explicitly (`fetch(...)`, `updatePage(0)`, etc.).
|
|
90
|
-
- After the source is initialized, the grid
|
|
88
|
+
- After the source is initialized, the grid prefers `source.loadPage(...)` for explicit page results and uses `source.updatePage(...)` only as the deprecated compatibility fallback.
|
|
91
89
|
- If the source exposes `updatePageSize(...)`, the grid uses it when the page size changes.
|
|
92
90
|
- If the source exposes `sort`, `updateSort(...)`, or `updateSorts(...)`, the grid keeps sort state in sync and can delegate user sorting directly to the source.
|
|
93
|
-
- Infinity buffering uses `prefetchMode: 'sequential'` by default
|
|
94
|
-
- Set `prefetchMode: 'parallel'` only for sources that
|
|
91
|
+
- Infinity buffering uses `prefetchMode: 'sequential'` by default. `prefetchMode: 'parallel'` requires a truly stateless `loadPage(...)`; keep `PagedQueryStore` and other latest-wins stateful sources sequential unless they expose that capability.
|
|
92
|
+
- Set `prefetchMode: 'parallel'` only for sources that provide explicit page-local results through `loadPage(...)`.
|
|
95
93
|
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
Request ownership:
|
|
95
|
+
|
|
96
|
+
- Without `source`, paginator actions and `requestPage()` emit `pageChange`; the parent owns fetching and updates `[data]` itself.
|
|
97
|
+
- With `source`, paginator actions, `requestPage()`, `requestPageSize()`, and `retryPage()` use the source request path and do **not** emit `pageChange`. Do not also fetch from `(pageChange)` when `[source]` is bound.
|
|
98
|
+
- A page-size change calls `updatePageSize(size)` once when that optional capability exists. The source owns resetting to and loading page zero as part of that operation.
|
|
99
|
+
- A sort starts a new dataset generation. It aborts or discards stale stateless page results; stateful `updatePage()` sources must keep their own latest-wins behavior. Page actions received while a source sort request is active are ignored.
|
|
100
|
+
|
|
101
|
+
## `PagedQueryStore` from `@reforgium/statum` fits this contract directly, so `[source]="store"` is enough for the common server-table case.
|
|
98
102
|
|
|
99
103
|
## Configuration
|
|
100
104
|
|
|
@@ -140,7 +144,8 @@ Supported default fields:
|
|
|
140
144
|
- `translations`
|
|
141
145
|
- `debounce`
|
|
142
146
|
|
|
143
|
-
`translations` supports: `emptyState`, `itemsPerPageLabel`,
|
|
147
|
+
`translations` supports: `emptyState`, `itemsPerPageLabel`,
|
|
148
|
+
extPageLabel`, `prevPageLabel`, `indexColumnHeader`.
|
|
144
149
|
|
|
145
150
|
### Global header text resolver
|
|
146
151
|
|
|
@@ -183,9 +188,7 @@ You can register type-based transformers and renderers globally via DI.
|
|
|
183
188
|
- `reDataGridTypeCell="..."` registers an instance-local renderer (only for that grid instance)
|
|
184
189
|
|
|
185
190
|
```ts
|
|
186
|
-
import {
|
|
187
|
-
provideDataGridTypeTransformers,
|
|
188
|
-
} from '@reforgium/data-grid';
|
|
191
|
+
import { provideDataGridTypeTransformers } from '@reforgium/data-grid';
|
|
189
192
|
|
|
190
193
|
export const routes: Routes = [
|
|
191
194
|
{
|
|
@@ -201,9 +204,7 @@ export const routes: Routes = [
|
|
|
201
204
|
```
|
|
202
205
|
|
|
203
206
|
```ts
|
|
204
|
-
columns = [
|
|
205
|
-
{ key: 'salary', header: 'Salary', type: 'money' },
|
|
206
|
-
];
|
|
207
|
+
columns = [{ key: 'salary', header: 'Salary', type: 'money' }];
|
|
207
208
|
```
|
|
208
209
|
|
|
209
210
|
```html
|
|
@@ -257,46 +258,57 @@ columns = [
|
|
|
257
258
|
<ng-template reDataGridTypeCell="money" let-value="value" let-isPinned="isPinned">
|
|
258
259
|
<b>{{ value }}</b>
|
|
259
260
|
@if (isPinned) {
|
|
260
|
-
|
|
261
|
+
<small>PIN</small>
|
|
261
262
|
}
|
|
262
263
|
</ng-template>
|
|
263
264
|
```
|
|
264
265
|
|
|
265
266
|
### Inputs
|
|
266
267
|
|
|
267
|
-
| Parameter
|
|
268
|
-
|
|
269
|
-
| data
|
|
270
|
-
| source
|
|
271
|
-
| columns
|
|
272
|
-
| headerGroups
|
|
273
|
-
| pinnedRows
|
|
274
|
-
| isRowSticky
|
|
275
|
-
| isRowDisabled
|
|
276
|
-
| getRowTemplate
|
|
277
|
-
| sortMode
|
|
278
|
-
| pageSize
|
|
279
|
-
| pageStartFromZero
|
|
280
|
-
| hasIndexColumn
|
|
281
|
-
| selection
|
|
282
|
-
|
|
|
283
|
-
|
|
|
284
|
-
|
|
|
285
|
-
|
|
|
286
|
-
|
|
|
287
|
-
|
|
|
288
|
-
|
|
|
289
|
-
|
|
|
290
|
-
|
|
|
291
|
-
|
|
|
292
|
-
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
-
|
|
268
|
+
| Parameter | Type | Default | Description |
|
|
269
|
+
|---------------------|-----------------------------------------------------|-----------------------|----------------------------------------------------------------|
|
|
270
|
+
| data | `T[]` | `[]` | Data array to render. |
|
|
271
|
+
| source | `GridPagedDataSource<T> \| null` | `null` | Page-oriented source for pagination and infinity flows. |
|
|
272
|
+
| columns | `GridColumn<T>[]` | `[]` | Programmatic column configuration. |
|
|
273
|
+
| headerGroups | `GridHeaderGroup<T>[]` | `[]` | Optional two-level header groups. |
|
|
274
|
+
| pinnedRows | `GridPinnedRow<T>[]` | `[]` | Top and bottom pinned rows. |
|
|
275
|
+
| isRowSticky | `(row: T, index: number) => boolean` | `undefined` | Predicate for sticky data rows. |
|
|
276
|
+
| isRowDisabled | `(row: T, index: number) => boolean` | `undefined` | Predicate for disabled rows. |
|
|
277
|
+
| getRowTemplate | `(row: T, index: number) => TemplateRef \| null` | `undefined` | Optional custom row template resolver. |
|
|
278
|
+
| sortMode | `'single' \| 'multi'` | `'single'` | Sorting mode for header actions. |
|
|
279
|
+
| pageSize | `number` | `20` | Page size for pagination and infinity modes. |
|
|
280
|
+
| pageStartFromZero | `boolean` | `true` | Whether page indices start from zero. |
|
|
281
|
+
| hasIndexColumn | `boolean` | `false` | Whether to add the index column. |
|
|
282
|
+
| selection | `GridSelection<T>` | `{ mode: 'none' }` | Row selection configuration. |
|
|
283
|
+
| selectedKeys | `ReadonlyArray<GridSelectionValue<T>> \| undefined` | `undefined` | Controlled selection values. |
|
|
284
|
+
| selectionPolicy | `'preserve-unloaded' \| 'loaded-only'` | `'preserve-unloaded'` | Cross-page selection reconciliation policy. |
|
|
285
|
+
| rowHeight | `number` | `40` | Fixed data-row height in pixels. |
|
|
286
|
+
| virtualBuffer | `number` | `8` | Extra virtual rows above and below the viewport. |
|
|
287
|
+
| lockVerticalScroll | `boolean` | `false` | Locks vertical while retaining horizontal scroll. |
|
|
288
|
+
| height | `number \| 'full' \| 'default'` | `'default'` | Grid height in pixels, full height, or the configured default. |
|
|
289
|
+
| loading | `boolean` | `false` | Fallback loading state when no source is provided. |
|
|
290
|
+
| loadingMode | `'spinner' \| 'skeleton'` | `'spinner'` | Loading presentation. |
|
|
291
|
+
| deferContent | `boolean` | `true` | Defers main-content rendering. |
|
|
292
|
+
| deferHeader | `boolean` | `false` | Defers header rendering. |
|
|
293
|
+
| deferPinned | `boolean` | `false` | Defers pinned-row rendering. |
|
|
294
|
+
| deferCells | `boolean` | `false` | Defers cell-content rendering. |
|
|
295
|
+
| rowKey | `DataKey<T> \| ((item: T) => string \| number)` | `undefined` | Stable row identity property or resolver. |
|
|
296
|
+
|
|
297
|
+
When selection mode is `'single'` or `'multi'`, provide a `key` (data property). Use `defaultSelectedKeys` for uncontrolled initial state. `defaultSelected` remains supported but is deprecated.
|
|
298
|
+
Row identity and virtual rendering:
|
|
299
|
+
|
|
300
|
+
- `rowKey` is the Angular render key for virtual data rows. Supply a unique stable property or resolver whenever rows can be reordered, replaced, or contain stateful templates.
|
|
301
|
+
- Without `rowKey`, rows are tracked by absolute dataset index. This prevents stale slot state, but a reorder recreates affected row views rather than preserving them by record identity.
|
|
302
|
+
- Column `track` is accepted for compatibility but deprecated and ignored by the renderer; use `rowKey`.
|
|
303
|
+
|
|
304
|
+
Selection ownership and page policy:
|
|
305
|
+
|
|
306
|
+
- Leave `selectedKeys` unset for uncontrolled selection. The grid keeps its local state and emits both `selectChange` and `selectedKeysChange`.
|
|
307
|
+
- Bind `selectedKeys` and handle `selectedKeysChange` for controlled selection. The grid emits a proposal and immediately restores the input value until the consumer supplies the next value.
|
|
308
|
+
- `selectionPolicy` defaults to `'preserve-unloaded'`, so selected keys survive pagination, infinity page buffering, and background prefetch even when their rows are not currently rendered.
|
|
309
|
+
- Set `selectionPolicy="loaded-only"` only when each loaded collection is the complete selection scope; it prunes selected values absent from the current loaded rows.
|
|
310
|
+
- `selectAllLoaded()` and the header checkbox operate on loaded/current-page rows only. They add or remove those values while preserving selections from other pages; server-wide selection is intentionally not modeled by this API.
|
|
311
|
+
- For compile-time correlation between the configured key and selected values, declare configuration as `GridSelectionByKey<Row, 'id'>`; the legacy `GridSelection<Row>` remains permissive for compatibility.
|
|
300
312
|
|
|
301
313
|
Data source guidance:
|
|
302
314
|
|
|
@@ -304,14 +316,17 @@ Data source guidance:
|
|
|
304
316
|
- Use `source` for server-driven pagination or infinity flows where the parent should expose only the current page.
|
|
305
317
|
- In `mode="infinity"` + `source`, the grid uses `totalElements` for scroll height when available and stores loaded page chunks internally instead of forcing the parent to append rows into one large array.
|
|
306
318
|
- `GridPagedDataSource.totalElements` is optional for source-driven infinity and pagination flows.
|
|
319
|
+
- Mutable infinity sources should expose `version` and increment it after replacement/filter/sort changes. An immutable source may set `immutable: true` and omit `version`, but it must never replace data in place; assign a new source instance for a new dataset.
|
|
307
320
|
- In `mode="infinity"`, if `totalElements` is omitted, the grid keeps requesting pages until it receives a short page (`items.length < pageSize`) and then treats that page as the end of the dataset.
|
|
308
321
|
- In `mode="pagination"`, if `totalElements` is omitted, the grid exposes one optimistic extra page while the current page is full. The final size becomes known only after a short page is returned.
|
|
309
322
|
- In `source` mode, initialize the source from the parent after all filters / params are ready; the grid does not perform an automatic first fetch on mount.
|
|
310
323
|
- `GridPagedDataSource.error` is optional and can be used by consumers that want to project source-level error UI near the grid.
|
|
324
|
+
- When a request fails and the source does not expose `error`, the grid emits `sourceError` with its operation (`page`, `page-size`, `sort`, `multi-sort`, or `prefetch`) and applicable page/sort context. Abort and stale results do not emit errors.
|
|
325
|
+
- Use `retryPage()` to repeat the current source page (or pass a page explicitly). It follows the same source request path as user pagination; retry UI remains consumer-owned.
|
|
311
326
|
- `GridPagedDataSource.sort`, `updateSort(...)`, and `updateSorts(...)` let the grid use source-owned sort state instead of forcing a separate parent bridge.
|
|
312
327
|
- `GridPagedDataSource.prefetchMode` defaults to `sequential`; keep that default for `PagedQueryStore` and similar latest-wins sources.
|
|
313
|
-
- Use `prefetchMode: 'parallel'` only when the source
|
|
314
|
-
- When `source.version` changes
|
|
328
|
+
- Use `prefetchMode: 'parallel'` only when the source exposes `loadPage(...)`; the explicit page result keeps concurrent responses page-local.
|
|
329
|
+
- When `source.version` changes, a new source is assigned, or `resetSourceBuffer()` is called, the grid invalidates its internal buffer immediately; grid-owned sort and page-size changes also invalidate it. Any in-flight `loadPage()` or `updatePage()` responses that arrive after invalidation are discarded and do not overwrite the fresh buffer.
|
|
315
330
|
|
|
316
331
|
Feature lazy-loading behavior (runtime `import()`):
|
|
317
332
|
|
|
@@ -322,7 +337,7 @@ Feature lazy-loading behavior (runtime `import()`):
|
|
|
322
337
|
|
|
323
338
|
Loading behavior:
|
|
324
339
|
|
|
325
|
-
- `loadingMode="spinner"`: shows centered spinner
|
|
340
|
+
- `loadingMode="spinner"`: shows a centered blocking spinner only while the source has no renderable rows; background prefetch keeps existing rows interactive.
|
|
326
341
|
- `loadingMode="skeleton"` + `mode="infinity"` + `loading=true`: appends 4 skeleton rows at the end of the current data.
|
|
327
342
|
- `loadingMode="skeleton"` + `mode="pagination"` + `loading=true` + empty data: renders 4 skeleton rows in the table body.
|
|
328
343
|
|
|
@@ -332,7 +347,6 @@ Sticky rows:
|
|
|
332
347
|
- You can customize the sticky row rendering with `reDataGridStickyRow` template.
|
|
333
348
|
|
|
334
349
|
```html
|
|
335
|
-
|
|
336
350
|
<re-data-grid [data]="items" [columns]="columns" [isRowSticky]="isSticky">
|
|
337
351
|
<ng-template reDataGridStickyRow let-row let-index="index">
|
|
338
352
|
<div class="my-sticky-row">{{ index + 1 }}. {{ row.name }}</div>
|
|
@@ -346,7 +360,6 @@ Row templates:
|
|
|
346
360
|
- Use `reDataGridRow` as a default row template.
|
|
347
361
|
|
|
348
362
|
```html
|
|
349
|
-
|
|
350
363
|
<re-data-grid [data]="items" [columns]="columns" [getRowTemplate]="rowTpl">
|
|
351
364
|
<ng-template reDataGridRow let-index="index">
|
|
352
365
|
<div class="my-row">{{ index + 1 }}. {{ row.name }}</div>
|
|
@@ -356,25 +369,28 @@ Row templates:
|
|
|
356
369
|
|
|
357
370
|
### Outputs
|
|
358
371
|
|
|
359
|
-
| Event
|
|
360
|
-
|
|
361
|
-
| cellClick
|
|
362
|
-
| cellContext
|
|
363
|
-
| cellDoubleClick
|
|
364
|
-
| rowClick
|
|
365
|
-
| rowContext
|
|
366
|
-
| rowDoubleClick
|
|
367
|
-
| columnResizeEnd
|
|
368
|
-
| sortChange
|
|
369
|
-
| multiSortChange
|
|
370
|
-
| pageChange
|
|
371
|
-
|
|
|
372
|
+
| Event | Type | Description | |
|
|
373
|
+
|--------------------|----------------------------------------|--------------------------------------------------------------------------------|-------------------|
|
|
374
|
+
| cellClick | `GridCellClickEvent<T>` | Emitted when a cell is clicked (includes native event) | _[UPD in 2.0.0]_ |
|
|
375
|
+
| cellContext | `GridCellContextEvent<T>` | Emitted on cell context menu | _[NEW in 2.0.0]_ |
|
|
376
|
+
| cellDoubleClick | `GridCellDoubleClickEvent<T>` | Emitted when a cell is double-clicked | _[NEW in 2.0.0]_ |
|
|
377
|
+
| rowClick | `GridRowClickEvent<T>` | Emitted when a row is clicked (includes native event) | _[UPD in 2.0.0]_ |
|
|
378
|
+
| rowContext | `GridRowContextEvent<T>` | Emitted on row context menu | _[NEW in 2.0.0]_ |
|
|
379
|
+
| rowDoubleClick | `GridRowDoubleClickEvent<T>` | Emitted when a row is double-clicked | _[NEW in 2.0.0]_ |
|
|
380
|
+
| columnResizeEnd | `GridColumnResizeEndEvent<T>` | Emitted when a column resize drag ends (key + px width); use to persist widths | _[NEW in 3.1.0]_ |
|
|
381
|
+
| sortChange | `GridSortEvent<T>` | Emitted when single-sort order changes | |
|
|
382
|
+
| multiSortChange | `GridMultiSortEvent<T>` | Emitted when multi-sort order changes | _[NEW in 2.2.0]_ |
|
|
383
|
+
| pageChange | `GridPageChangeEvent` | Emitted for page requests only when `[source]` is not bound | |
|
|
384
|
+
| sourceError | `GridSourceRequestErrorEvent<T>` | Fallback source-request failure when `source.error` is not available | _[NEW in 3.3.0]_ |
|
|
385
|
+
| selectChange | `GridSelectEvent<T>` | Emitted when selected row values change | |
|
|
386
|
+
| selectedKeysChange | `ReadonlyArray<GridSelectionValue<T>>` | Controlled-selection proposal emitted after an interaction | _[NEW in 3.3.0]_ |
|
|
372
387
|
|
|
373
388
|
Notes:
|
|
374
389
|
|
|
375
390
|
- A cell click also triggers the row click event (bubbling), so listen to one or stop propagation if needed.
|
|
376
391
|
- In `source` mode, sort events are still emitted, but if the source implements sort hooks the grid also updates the source directly.
|
|
377
|
-
- `selectChange`
|
|
392
|
+
- `selectChange` remains the compatibility event for all selection changes. In controlled mode, use `selectedKeysChange` to update the bound `selectedKeys` value.
|
|
393
|
+
- With the default `'preserve-unloaded'` policy, page changes do not emit selection changes. `'loaded-only'` may emit an empty or reduced selection when the loaded dataset changes, and changing the configured selection key resets selection.
|
|
378
394
|
|
|
379
395
|
### Public API methods
|
|
380
396
|
|
|
@@ -383,6 +399,10 @@ Notes:
|
|
|
383
399
|
- `clearSelection()` - clears current selection and emits `selectChange`
|
|
384
400
|
- `selectAllLoaded()` - selects currently loaded rows (multi mode) and emits `selectChange`
|
|
385
401
|
- `resetSort()` - resets sort state and emits sort events
|
|
402
|
+
- `resetSourceBuffer()` - clears the grid-owned source buffer and invalidates in-flight page results
|
|
403
|
+
- `requestPage(page)` - requests a page through the source contract or legacy `pageChange` output
|
|
404
|
+
- `requestPageSize(size)` - changes size through the shared page request path, starting at page zero
|
|
405
|
+
- `retryPage(page?)` - retries the current or supplied source page
|
|
386
406
|
- `setSort(event)` - applies single-sort state and emits sort events
|
|
387
407
|
- `setMultiSort(items)` - applies multi-sort state and emits sort events
|
|
388
408
|
|
|
@@ -390,52 +410,78 @@ Notes:
|
|
|
390
410
|
|
|
391
411
|
The optional `source` input accepts a page-oriented contract:
|
|
392
412
|
|
|
393
|
-
| Field / method
|
|
394
|
-
|
|
395
|
-
| `items`
|
|
396
|
-
| `loading`
|
|
397
|
-
| `error`
|
|
398
|
-
| `page`
|
|
399
|
-
| `pageSize`
|
|
400
|
-
| `totalElements`
|
|
401
|
-
| `sort`
|
|
402
|
-
| `version`
|
|
403
|
-
| `
|
|
404
|
-
| `
|
|
405
|
-
| `
|
|
406
|
-
| `
|
|
407
|
-
| `
|
|
413
|
+
| Field / method | Type | Description | |
|
|
414
|
+
|---------------------------|--------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|
|
|
415
|
+
| `items` | `Signal<T[]>` | Current page items. |
|
|
416
|
+
| `loading` | `Signal<boolean>` | Source loading state. |
|
|
417
|
+
| `error` | `Signal<unknown \| null> \| undefined` | Optional source error state. |
|
|
418
|
+
| `page` | `number` | Current page index. |
|
|
419
|
+
| `pageSize` | `number` | Current page size. |
|
|
420
|
+
| `totalElements` | `number \| undefined` | Optional exact dataset size. Without it, infinity ends at a short page and pagination exposes one optimistic extra page while the current page is full. |
|
|
421
|
+
| `sort` | `ReadonlyArray<GridSortItem<T>> \| undefined` | Optional source-owned sort state. |
|
|
422
|
+
| `version` | `Signal<number> | undefined` | Dataset reset marker for local buffer invalidation. |
|
|
423
|
+
| `immutable` | `boolean | undefined` | Opt in only when the dataset never changes for this source instance; replace the source instance for a new dataset. |
|
|
424
|
+
| `loadPage(page, options)` | `(page: number, options?: GridPageRequestOptions) => Promise<GridPageResult<T>>` | Preferred stateless loader; result must include the requested page identity and items. |
|
|
425
|
+
| `updatePage(page)` | `((page: number) => Promise<unknown>) \| undefined` | Deprecated stateful compatibility fallback. |
|
|
426
|
+
| `updatePageSize(size)` | `((size: number) => Promise<unknown>) \| undefined` | Optional page-size handler that resets and loads page zero. |
|
|
427
|
+
| `updateSort(sort)` | `((sort?: GridSortItem<T> \| null) => Promise<unknown>) \| undefined` | Optional single-sort handler. |
|
|
428
|
+
| `updateSorts(sort)` | `((sort?: ReadonlyArray<GridSortItem<T>> \| null) => Promise<unknown>) \| undefined` | Optional multi-sort handler. |
|
|
429
|
+
| `prefetchMode` | `'sequential' \| 'parallel' \| undefined` | Infinity strategy; `parallel` requires `loadPage`. |
|
|
408
430
|
|
|
409
431
|
This contract is intentionally grid-like, not `statum`-specific, but `PagedQueryStore` already matches it well enough to be used directly.
|
|
410
432
|
|
|
433
|
+
#### Generic stateless source
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
const source: GridPagedDataSource<User> = {
|
|
437
|
+
items,
|
|
438
|
+
loading,
|
|
439
|
+
page: 0,
|
|
440
|
+
pageSize: 25,
|
|
441
|
+
totalElements: 0,
|
|
442
|
+
async loadPage(page, { signal } = {}) {
|
|
443
|
+
const response = await api.users({ page, size: this.pageSize, signal });
|
|
444
|
+
return { page, items: response.items, totalElements: response.total };
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Use `prefetchMode: 'parallel'` only with this kind of page-local `loadPage` result. The grid aborts superseded stateless loads through `GridPageRequestOptions.signal` and ignores stale results.
|
|
450
|
+
|
|
451
|
+
#### Stateful latest-wins source
|
|
452
|
+
|
|
453
|
+
A `PagedQueryStore`-like source that mutates shared `items`, `page`, and `loading` in `updatePage` is supported through the compatibility fallback. Keep `prefetchMode: 'sequential'`; concurrent calls cannot safely share a single mutable page state. Expose `version` or call `resetSourceBuffer()` after external dataset replacement.
|
|
454
|
+
|
|
411
455
|
### GridColumn<T> reference
|
|
412
456
|
|
|
413
457
|
`columns` accepts `GridColumn<T>[]`, where `GridColumn<T>` is a union of three column variants:
|
|
414
458
|
|
|
415
459
|
- default column (`type` + optional `typeParams`)
|
|
416
|
-
- value column (`value`
|
|
417
|
-
- template column (`renderTemplate`
|
|
460
|
+
- value column (`value`)
|
|
461
|
+
- template column (`renderTemplate`)
|
|
418
462
|
|
|
419
463
|
Common (base) fields:
|
|
420
464
|
|
|
421
|
-
| Field | Type | Description
|
|
422
|
-
|
|
423
|
-
| `
|
|
424
|
-
| `
|
|
425
|
-
| `
|
|
426
|
-
| `
|
|
427
|
-
| `
|
|
428
|
-
| `
|
|
429
|
-
| `
|
|
430
|
-
| `
|
|
431
|
-
|
|
465
|
+
| Field | Type | Description |
|
|
466
|
+
|-------------------------|-----------------------------------------------------------------------------|------------------------------------------------------------------------------|
|
|
467
|
+
| `key` | `DataKey<T>` | Unique column identifier. |
|
|
468
|
+
| `sortKey` | `DataKey<T>` | Sort key; use `gridBackendSortField(...)` for an explicit server-only field. |
|
|
469
|
+
| `sticky` | `'left' \| 'right' \| true` | Keeps the column fixed; `true` pins it left. |
|
|
470
|
+
| `expandBy` | `DataKey<T>` | Data key for expand/collapse. |
|
|
471
|
+
| `flex` | `number` | Flex-grow factor for width distribution. |
|
|
472
|
+
| `minWidth` / `maxWidth` | `number` | Column width limits in pixels. |
|
|
473
|
+
| `resizable` | `boolean` | Enables header drag resize. |
|
|
474
|
+
| `cellClass` | `string \| ((row: T) => string)` | Static class or per-row resolver. |
|
|
475
|
+
| `tooltip` | `true \| string \| ((row: T) => string) \| TemplateRef<GridTooltipContext>` | Tooltip content; `true` uses the cell value. |
|
|
476
|
+
|
|
477
|
+
For server-only sort fields that are not properties of the displayed row, use `gridBackendSortField('server_field')`. It is an explicit, branded string accepted by the current compatibility API. Legacy arbitrary strings remain supported, but a future major release can narrow `DataKey<T>` to actual row keys.
|
|
432
478
|
Renderer-specific fields:
|
|
433
479
|
|
|
434
|
-
| Variant
|
|
435
|
-
|
|
436
|
-
| Built-in / type renderer
|
|
437
|
-
| Value renderer
|
|
438
|
-
| Template renderer
|
|
480
|
+
| Variant | Fields | Notes |
|
|
481
|
+
|---------------------------|-----------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|
|
|
482
|
+
| Built-in / type renderer | `type?: GridBuiltInCellType \| string`, `typeParams?: any`, `defaultValue?: any` | Built-in types are `plain/date/number/index/checkbox`; custom string types can be handled by local/DI type registries. |
|
|
483
|
+
| Value renderer | `value: (row: T, ctx) => string \| number` | Row identity comes from grid-level `rowKey`; `ctx` includes `col`, `index`, `isPinned`. |
|
|
484
|
+
| Template renderer | `renderTemplate: TemplateRef<...>` | Row identity comes from grid-level `rowKey`. |
|
|
439
485
|
|
|
440
486
|
Cell text wrapping/clamp behavior:
|
|
441
487
|
|
|
@@ -443,12 +489,11 @@ Cell text wrapping/clamp behavior:
|
|
|
443
489
|
- Template-based renderers (`renderTemplate`, `reDataGridCell`, `reDataGridTypeCell`, etc.) are not clamped by default and are fully controlled by your template styles.
|
|
444
490
|
- Cell template contexts also include `isPinned` so pinned top/bottom rows can be rendered differently.
|
|
445
491
|
|
|
446
|
-
### Declarative columns
|
|
492
|
+
### Declarative columns _[NEW in 2.0.0]_
|
|
447
493
|
|
|
448
494
|
You can define columns directly in markup via `<re-dg-column>`, then the grid will normalize them to `GridColumn<T>` internally.
|
|
449
495
|
|
|
450
496
|
```html
|
|
451
|
-
|
|
452
497
|
<re-data-grid [data]="items" [rowKey]="'id'">
|
|
453
498
|
<re-dg-column key="name">
|
|
454
499
|
<ng-template reHeader>Name</ng-template>
|
|
@@ -473,7 +518,7 @@ Notes:
|
|
|
473
518
|
- When used with column manager state, `visible`, `disabled`, and `sticky` are taken from state when defined.
|
|
474
519
|
- `reHeader` maps to `headerTemplate`.
|
|
475
520
|
- `reCell` receives value as `$implicit`, and the row is available as `let-row="row"` via `RenderTemplateData`.
|
|
476
|
-
- Most `GridColumn<T>` fields are available as `<re-dg-column>` inputs (`sortKey`, `sticky`, `expandBy`, `disabled`, `width`, `minWidth`, `maxWidth`, `flex`, `resizable`, `align`, `cellClass`, `type`, `typeParams`, `defaultValue`, `value`, `
|
|
521
|
+
- Most `GridColumn<T>` fields are available as `<re-dg-column>` inputs (`sortKey`, `sticky`, `expandBy`, `disabled`, `width`, `minWidth`, `maxWidth`, `flex`, `resizable`, `align`, `cellClass`, `type`, `typeParams`, `defaultValue`, `value`, `tooltip`). `track` is deprecated; use `rowKey`.
|
|
477
522
|
- `sticky` accepts `'left' | 'right'`; legacy `true` maps to `'left'` for backward compatibility.
|
|
478
523
|
|
|
479
524
|
### Tooltip
|
|
@@ -491,7 +536,6 @@ columns = [
|
|
|
491
536
|
Template tooltip:
|
|
492
537
|
|
|
493
538
|
```html
|
|
494
|
-
|
|
495
539
|
<ng-template #tip let-row let-col="col" let-index="index" let-value="value">
|
|
496
540
|
<div><b>{{ col.header }}</b> #{{ index + 1 }}</div>
|
|
497
541
|
<div>{{ value }}</div>
|
|
@@ -507,18 +551,18 @@ Tooltip template context (`GridTooltipContext`):
|
|
|
507
551
|
- `index`
|
|
508
552
|
- `value`
|
|
509
553
|
|
|
510
|
-
### Header groups
|
|
554
|
+
### Header groups _[NEW in 2.0.0]_
|
|
511
555
|
|
|
512
556
|
Use `headerGroups` to render an optional top header row (2-level header layout) above regular column headers.
|
|
513
557
|
|
|
514
|
-
| Field
|
|
515
|
-
|
|
516
|
-
| `key`
|
|
517
|
-
| `from`
|
|
518
|
-
| `to`
|
|
519
|
-
| `title`
|
|
520
|
-
| `titleTemplate`
|
|
521
|
-
| `align`
|
|
558
|
+
| Field | Type | Description |
|
|
559
|
+
|-------------------|-----------------------------------|------------------------------------------------------------------|
|
|
560
|
+
| `key` | `string` | Unique id of the header group. |
|
|
561
|
+
| `from` | `DataKey<T>` | Start column key (inclusive). |
|
|
562
|
+
| `to` | `DataKey<T>` | End column key (inclusive). If omitted, group covers one column. |
|
|
563
|
+
| `title` | `string` | Plain text title for the group. |
|
|
564
|
+
| `titleTemplate` | `TemplateRef<HeaderTemplateData>` | Template-based title for the group. |
|
|
565
|
+
| `align` | `'left' \| 'center' \| 'right'` | Optional group title alignment (plain title variant). |
|
|
522
566
|
|
|
523
567
|
Notes:
|
|
524
568
|
|
|
@@ -530,15 +574,15 @@ Notes:
|
|
|
530
574
|
|
|
531
575
|
| Directive | Parameters | Description | |
|
|
532
576
|
|------------------------|-----------------------------------|---------------------------------------------------|------------------|
|
|
533
|
-
| reHeader | - | Declarative header template inside `re-dg-column` |
|
|
534
|
-
| reCell | let-row |
|
|
577
|
+
| reHeader | - | Declarative header template inside `re-dg-column` | _[NEW in 2.0.0]_ |
|
|
578
|
+
| reCell | let-row | Declarative cell template inside `re-dg-column` | _[NEW in 2.0.0]_ |
|
|
535
579
|
| reDataGridHeader | key: string | Template for specific column header by key | |
|
|
536
|
-
| reDataGridCell | key: string | Template for specific column cell by key |
|
|
580
|
+
| reDataGridCell | key: string | Template for specific column cell by key | _[NEW in 1.1.0]_ |
|
|
537
581
|
| reDataGridTypeCell | type: string | Template for cells of a specific column type | |
|
|
538
582
|
| reDataGridEmpty | - | Template for the empty state (no data) | |
|
|
539
583
|
| reDataGridLoading | - | Template for the loading state | |
|
|
540
|
-
| reDataGridSortIcon | order: GridSortOrder \| undefined | Template for custom sorting icon |
|
|
541
|
-
| reDataGridExpanderIcon | expanded: boolean | Template for custom expander icon |
|
|
584
|
+
| reDataGridSortIcon | order: GridSortOrder \| undefined | Template for custom sorting icon | _[NEW in 1.1.0]_ |
|
|
585
|
+
| reDataGridExpanderIcon | expanded: boolean | Template for custom expander icon | _[NEW in 1.1.0]_ |
|
|
542
586
|
|
|
543
587
|
### CSS Variables
|
|
544
588
|
|
|
@@ -682,38 +726,37 @@ Misc:
|
|
|
682
726
|
|
|
683
727
|
---
|
|
684
728
|
|
|
685
|
-
## Paginator
|
|
729
|
+
## Paginator _[NEW in 1.1.0]_
|
|
686
730
|
|
|
687
731
|
The paginator component is used to display a page selector and total count.
|
|
688
732
|
|
|
689
733
|
### Inputs
|
|
690
734
|
|
|
691
|
-
| Parameter | Type
|
|
692
|
-
|
|
693
|
-
| current | `number`
|
|
694
|
-
| pageSize | `number`
|
|
695
|
-
| totalElements | `number`
|
|
696
|
-
| maxShowPages | `number`
|
|
697
|
-
| showFirstLast | `boolean`
|
|
698
|
-
| showPerPage | `boolean`
|
|
699
|
-
| pageSizeOptions | `number[]`
|
|
700
|
-
| perPageLabel | `string`
|
|
701
|
-
| firstLabel | `string`
|
|
702
|
-
| lastLabel | `string`
|
|
735
|
+
| Parameter | Type | Default | Description |
|
|
736
|
+
|-----------------|-------------|-------------------|----------------------------------------|
|
|
737
|
+
| current | `number` | `0` | Current page |
|
|
738
|
+
| pageSize | `number` | `0` | Number of items per page |
|
|
739
|
+
| totalElements | `number` | `0` | Total number of elements |
|
|
740
|
+
| maxShowPages | `number` | `7` | Maximum number of page buttons to show |
|
|
741
|
+
| showFirstLast | `boolean` | `false` | Show "First" and "Last" buttons |
|
|
742
|
+
| showPerPage | `boolean` | `false` | Show page-size dropdown |
|
|
743
|
+
| pageSizeOptions | `number[]` | `[10,20,50,100]` | Options for per-page dropdown |
|
|
744
|
+
| perPageLabel | `string` | `Items per page:` | Label near dropdown |
|
|
745
|
+
| firstLabel | `string` | `First` | Fallback label for first-page button |
|
|
746
|
+
| lastLabel | `string` | `Last` | Fallback label for last-page button |
|
|
703
747
|
|
|
704
748
|
### Outputs
|
|
705
749
|
|
|
706
|
-
| Event
|
|
707
|
-
|
|
708
|
-
| pageChange
|
|
709
|
-
| pageSizeChange
|
|
750
|
+
| Event | Type | Description |
|
|
751
|
+
|-----------------|-----------|-----------------------------------------------------------------------|
|
|
752
|
+
| pageChange | `number` | Emitted when the page changes. Returns the new page index (0-based). |
|
|
753
|
+
| pageSizeChange | `number` | Emitted when per-page value changes. |
|
|
710
754
|
|
|
711
755
|
### Paginator templates
|
|
712
756
|
|
|
713
757
|
You can customize first/last controls with `ng-template`:
|
|
714
758
|
|
|
715
759
|
```html
|
|
716
|
-
|
|
717
760
|
<re-data-grid-paginator
|
|
718
761
|
showFirstLast
|
|
719
762
|
showPerPage
|
|
@@ -770,8 +813,8 @@ Page:
|
|
|
770
813
|
- `--re-data-grid-paginator-page-height` - page button height (`var(--re-data-grid-paginator-page-size)`)
|
|
771
814
|
- `--re-data-grid-paginator-page-paddings` - page button paddings (`0 0.5rem`)
|
|
772
815
|
- `--re-data-grid-paginator-page-border` - page button border (`1px solid var(--re-data-grid-paginator-separator-color, #e2e8f0)`)
|
|
773
|
-
- `--re-data-grid-paginator-page-separator-color` - page button border color (`var(--re-data-grid-separator-color, --border-color)`)
|
|
774
|
-
- `--re-data-grid-paginator-page-rounded` - page button border radius (`var(--re-data-grid-rounded, --radius-md)`)
|
|
816
|
+
- `--re-data-grid-paginator-page-separator-color` - page button border color (`var(--re-data-grid-separator-color, var(--border-color, #e2e8f0))`)
|
|
817
|
+
- `--re-data-grid-paginator-page-rounded` - page button border radius (`var(--re-data-grid-rounded, var(--radius-md, 0.375rem))`)
|
|
775
818
|
- `--re-data-grid-paginator-page-surface` - page button background (`var(--re-data-grid-surface, white)`)
|
|
776
819
|
- `--re-data-grid-paginator-page-color` - page button text color (`var(--text-primary, #1e293b)`)
|
|
777
820
|
- `--re-data-grid-paginator-page-font-size` - page button font size (`0.875rem`)
|
|
@@ -786,8 +829,7 @@ Hover Page:
|
|
|
786
829
|
- `--re-data-grid-paginator-page-hover-surface` - page button hover background (`var(--re-data-grid-active, #3b82f6)`)
|
|
787
830
|
- `--re-data-grid-paginator-page-hover-color` - page button hover text color (`white`)
|
|
788
831
|
|
|
789
|
-
|
|
790
|
-
### Column manager *[NEW in 2.0.0]*
|
|
832
|
+
### Column manager _[NEW in 2.0.0]_
|
|
791
833
|
|
|
792
834
|
Column manager is a secondary entrypoint that provides a dropdown UI for reordering, show/hide, and pinning columns.
|
|
793
835
|
|
|
@@ -796,7 +838,6 @@ import { DataGridColumnManager } from '@reforgium/data-grid/column-manager';
|
|
|
796
838
|
```
|
|
797
839
|
|
|
798
840
|
```html
|
|
799
|
-
|
|
800
841
|
<re-data-grid-column-manager
|
|
801
842
|
triggerLabel="Columns"
|
|
802
843
|
[columns]="managedColumns()"
|
|
@@ -809,7 +850,6 @@ import { DataGridColumnManager } from '@reforgium/data-grid/column-manager';
|
|
|
809
850
|
Custom trigger via content projection:
|
|
810
851
|
|
|
811
852
|
```html
|
|
812
|
-
|
|
813
853
|
<re-data-grid-column-manager
|
|
814
854
|
triggerLabel="Columns"
|
|
815
855
|
[columns]="managedColumns()"
|
|
@@ -822,10 +862,7 @@ Custom trigger via content projection:
|
|
|
822
862
|
Custom column title template (controls stay built-in):
|
|
823
863
|
|
|
824
864
|
```html
|
|
825
|
-
<re-data-grid-column-manager
|
|
826
|
-
[columns]="managedColumns()"
|
|
827
|
-
(columnsChange)="managedColumns.set($event)"
|
|
828
|
-
>
|
|
865
|
+
<re-data-grid-column-manager [columns]="managedColumns()" (columnsChange)="managedColumns.set($event)">
|
|
829
866
|
<ng-template reDataGridColumnManagerColumnTitle let-title let-column="column">
|
|
830
867
|
<span class="font-medium">{{ title }}</span>
|
|
831
868
|
</ng-template>
|
|
@@ -849,11 +886,7 @@ import {
|
|
|
849
886
|
|
|
850
887
|
```ts
|
|
851
888
|
@Component({
|
|
852
|
-
imports: [
|
|
853
|
-
DataGridColumnManager,
|
|
854
|
-
DataGridColumnManagerTriggerDirective,
|
|
855
|
-
DataGridColumnManagerColumnTitleDirective,
|
|
856
|
-
],
|
|
889
|
+
imports: [DataGridColumnManager, DataGridColumnManagerTriggerDirective, DataGridColumnManagerColumnTitleDirective],
|
|
857
890
|
})
|
|
858
891
|
export class ExampleComponent {}
|
|
859
892
|
```
|
|
@@ -930,16 +963,14 @@ Compact Mode Example:
|
|
|
930
963
|
Cell Template by Type
|
|
931
964
|
|
|
932
965
|
```html
|
|
933
|
-
|
|
934
966
|
<ng-template reDataGridTypeCell="link" let-row="row">
|
|
935
967
|
<a [href]="value" target="_blank">{{ value }}</a>
|
|
936
968
|
</ng-template>
|
|
937
969
|
```
|
|
938
970
|
|
|
939
|
-
Cell Template
|
|
971
|
+
Cell Template _[NEW in 1.1.0]_
|
|
940
972
|
|
|
941
973
|
```html
|
|
942
|
-
|
|
943
974
|
<ng-template reDataGridCell="fullName" let-row="row">
|
|
944
975
|
<span><b>{{ row.firstName }}</b> {{ row.lastName }}</span>
|
|
945
976
|
</ng-template>
|
|
@@ -948,7 +979,6 @@ Cell Template *[NEW in 1.1.0]*
|
|
|
948
979
|
Custom Header Template:
|
|
949
980
|
|
|
950
981
|
```html
|
|
951
|
-
|
|
952
982
|
<ng-template reDataGridHeader="name" let-value="value">
|
|
953
983
|
<span class="header-with-icon">
|
|
954
984
|
<icon name="user" size="20" />
|