igniteui-angular 21.1.0-rc.4 → 21.1.0

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.
Files changed (61) hide show
  1. package/README.md +29 -0
  2. package/fesm2022/igniteui-angular-grids-core.mjs +5 -3
  3. package/fesm2022/igniteui-angular-grids-core.mjs.map +1 -1
  4. package/fesm2022/igniteui-angular-grids-grid.mjs +6 -1
  5. package/fesm2022/igniteui-angular-grids-grid.mjs.map +1 -1
  6. package/fesm2022/igniteui-angular-grids-hierarchical-grid.mjs +1 -0
  7. package/fesm2022/igniteui-angular-grids-hierarchical-grid.mjs.map +1 -1
  8. package/fesm2022/igniteui-angular-grids-lite.mjs +2 -0
  9. package/fesm2022/igniteui-angular-grids-lite.mjs.map +1 -1
  10. package/fesm2022/igniteui-angular-simple-combo.mjs +1 -1
  11. package/fesm2022/igniteui-angular-simple-combo.mjs.map +1 -1
  12. package/lib/core/styles/components/grid/_grid-theme.scss +4 -1
  13. package/migrations/migration-collection.json +7 -0
  14. package/migrations/update-21_1_0_add-agent-skills/index.d.ts +3 -0
  15. package/migrations/update-21_1_0_add-agent-skills/index.js +46 -0
  16. package/package.json +4 -4
  17. package/skills/igniteui-angular-components/SKILL.md +71 -0
  18. package/skills/igniteui-angular-components/references/charts.md +447 -0
  19. package/skills/igniteui-angular-components/references/data-display.md +347 -0
  20. package/skills/igniteui-angular-components/references/directives.md +149 -0
  21. package/skills/igniteui-angular-components/references/feedback.md +141 -0
  22. package/skills/igniteui-angular-components/references/form-controls.md +298 -0
  23. package/skills/igniteui-angular-components/references/layout-manager.md +415 -0
  24. package/skills/igniteui-angular-components/references/layout.md +216 -0
  25. package/skills/igniteui-angular-components/references/setup.md +157 -0
  26. package/skills/igniteui-angular-grids/SKILL.md +110 -0
  27. package/skills/igniteui-angular-grids/references/data-operations.md +436 -0
  28. package/skills/igniteui-angular-grids/references/editing.md +480 -0
  29. package/skills/igniteui-angular-grids/references/features.md +218 -0
  30. package/skills/igniteui-angular-grids/references/paging-remote.md +388 -0
  31. package/skills/igniteui-angular-grids/references/state.md +448 -0
  32. package/skills/igniteui-angular-grids/references/structure.md +290 -0
  33. package/skills/igniteui-angular-grids/references/types.md +428 -0
  34. package/skills/igniteui-angular-theming/SKILL.md +530 -0
  35. package/styles/igniteui-angular-dark.css +1 -1
  36. package/styles/igniteui-angular.css +1 -1
  37. package/styles/igniteui-bootstrap-dark.css +1 -1
  38. package/styles/igniteui-bootstrap-light.css +1 -1
  39. package/styles/igniteui-dark-green.css +1 -1
  40. package/styles/igniteui-fluent-dark-excel.css +1 -1
  41. package/styles/igniteui-fluent-dark-word.css +1 -1
  42. package/styles/igniteui-fluent-dark.css +1 -1
  43. package/styles/igniteui-fluent-light-excel.css +1 -1
  44. package/styles/igniteui-fluent-light-word.css +1 -1
  45. package/styles/igniteui-fluent-light.css +1 -1
  46. package/styles/igniteui-indigo-dark.css +1 -1
  47. package/styles/igniteui-indigo-light.css +1 -1
  48. package/styles/maps/igniteui-angular-dark.css.map +1 -1
  49. package/styles/maps/igniteui-angular.css.map +1 -1
  50. package/styles/maps/igniteui-bootstrap-dark.css.map +1 -1
  51. package/styles/maps/igniteui-bootstrap-light.css.map +1 -1
  52. package/styles/maps/igniteui-dark-green.css.map +1 -1
  53. package/styles/maps/igniteui-fluent-dark-excel.css.map +1 -1
  54. package/styles/maps/igniteui-fluent-dark-word.css.map +1 -1
  55. package/styles/maps/igniteui-fluent-dark.css.map +1 -1
  56. package/styles/maps/igniteui-fluent-light-excel.css.map +1 -1
  57. package/styles/maps/igniteui-fluent-light-word.css.map +1 -1
  58. package/styles/maps/igniteui-fluent-light.css.map +1 -1
  59. package/styles/maps/igniteui-indigo-dark.css.map +1 -1
  60. package/styles/maps/igniteui-indigo-light.css.map +1 -1
  61. package/types/igniteui-angular-grids-lite.d.ts +2 -0
@@ -0,0 +1,388 @@
1
+ # Grid Paging, Remote Data & Virtualization
2
+
3
+ > **Part of the [`igniteui-angular-grids`](../SKILL.md) skill hub.**
4
+ > For grid import patterns and `viewChild` access — see [`data-operations.md`](./data-operations.md).
5
+ > For editing and validation — see [`editing.md`](./editing.md).
6
+ > For state persistence — see [`state.md`](./state.md).
7
+
8
+ ## Paging
9
+
10
+ > **Docs:** [Paging — Remote Paging](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/paging#remote-paging) (substitute URL prefix per grid type)
11
+
12
+ ### Using the Paginator Component
13
+
14
+ ```html
15
+ <igx-grid #grid
16
+ [data]="data()"
17
+ [primaryKey]="'id'"
18
+ height="600px">
19
+ <igx-column field="name"></igx-column>
20
+ <igx-column field="amount" dataType="number"></igx-column>
21
+
22
+ <igx-paginator
23
+ [perPage]="15"
24
+ [selectOptions]="[10, 15, 25, 50]"
25
+ [displayDensity]="'comfortable'">
26
+ </igx-paginator>
27
+ </igx-grid>
28
+ ```
29
+
30
+ ### Programmatic Paging
31
+
32
+ ```typescript
33
+ // Navigate pages
34
+ this.gridRef().paginator.page = 3;
35
+ this.gridRef().paginator.nextPage();
36
+ this.gridRef().paginator.previousPage();
37
+ this.gridRef().paginator.paginate(0); // go to first page
38
+
39
+ // Change page size
40
+ this.gridRef().paginator.perPage = 25;
41
+ ```
42
+
43
+ ### Paging Events
44
+
45
+ | Event | Description |
46
+ |---|---|
47
+ | `(paging)` | Fires before page changes (cancelable) |
48
+ | `(pagingDone)` | Fires after page has changed |
49
+ | `(perPageChange)` | Fires when page size changes |
50
+
51
+ ### Remote Paging
52
+
53
+ ```typescript
54
+ import { GridPagingMode } from 'igniteui-angular/grids/grid';
55
+
56
+ export class RemotePagingComponent {
57
+ data = signal<Product[]>([]);
58
+ totalCount = signal(0);
59
+ perPage = signal(15);
60
+ pagingMode = GridPagingMode.Remote;
61
+
62
+ gridRef = viewChild.required<IgxGridComponent>('grid');
63
+ private dataService = inject(ProductService);
64
+
65
+ constructor() {
66
+ this.loadPage(0);
67
+ }
68
+
69
+ onPagingDone(event: IPageEventArgs) {
70
+ this.loadPage(event.current);
71
+ }
72
+
73
+ onPerPageChange(perPage: number) {
74
+ this.perPage.set(perPage);
75
+ this.loadPage(0);
76
+ }
77
+
78
+ private loadPage(pageIndex: number) {
79
+ const skip = pageIndex * this.perPage();
80
+ this.dataService.getProducts({ skip, take: this.perPage() }).subscribe(result => {
81
+ this.data.set(result.data);
82
+ this.totalCount.set(result.totalCount);
83
+ });
84
+ }
85
+ }
86
+ ```
87
+
88
+ ```html
89
+ <igx-grid #grid
90
+ [data]="data()"
91
+ [primaryKey]="'id'"
92
+ [pagingMode]="pagingMode"
93
+ height="600px">
94
+ <igx-column field="name"></igx-column>
95
+ <igx-column field="price" dataType="number"></igx-column>
96
+
97
+ <igx-paginator
98
+ [perPage]="perPage()"
99
+ [totalRecords]="totalCount()"
100
+ (pagingDone)="onPagingDone($event)"
101
+ (perPageChange)="onPerPageChange($event)">
102
+ </igx-paginator>
103
+ </igx-grid>
104
+ ```
105
+
106
+ ## Remote Data Operations
107
+
108
+ > **Docs:** [Remote Data Operations](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/remote-data-operations) (substitute URL prefix per grid type)
109
+
110
+ ### The Problem
111
+
112
+ Grids perform sorting, filtering, and paging **client-side** by default. For large datasets, you must intercept these operations and delegate them to the server.
113
+
114
+ ### Complete Remote Data Pattern
115
+
116
+ This is the canonical pattern for server-side sorting, filtering, and virtualization. **You must disable the built-in client-side sorting/filtering** by applying `NoopSortingStrategy` and `NoopFilteringStrategy` on the grid:
117
+
118
+ ```typescript
119
+ import { Component, ChangeDetectionStrategy, signal, viewChild, inject, DestroyRef } from '@angular/core';
120
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
121
+ import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
122
+ import {
123
+ IForOfState,
124
+ ISortingEventArgs,
125
+ IFilteringExpressionsTree,
126
+ NoopSortingStrategy,
127
+ NoopFilteringStrategy
128
+ } from 'igniteui-angular/grids/core';
129
+ import { debounceTime, Subject } from 'rxjs';
130
+
131
+ @Component({
132
+ selector: 'app-remote-grid',
133
+ imports: [IGX_GRID_DIRECTIVES],
134
+ templateUrl: './remote-grid.component.html',
135
+ changeDetection: ChangeDetectionStrategy.OnPush
136
+ })
137
+ export class RemoteGridComponent {
138
+ data = signal<Order[]>([]);
139
+ totalCount = signal(0);
140
+ isLoading = signal(false);
141
+
142
+ // Noop strategies — disable built-in client-side sort/filter
143
+ noopSort = NoopSortingStrategy.instance();
144
+ noopFilter = NoopFilteringStrategy.instance();
145
+
146
+ gridRef = viewChild.required<IgxGridComponent>('grid');
147
+ private dataService = inject(OrderService);
148
+ private destroyRef = inject(DestroyRef);
149
+
150
+ private currentSort: ISortingEventArgs[] | undefined;
151
+ private currentFilter: IFilteringExpressionsTree | undefined;
152
+
153
+ // Debounce rapid dataPreLoad events during fast scrolling
154
+ private dataPreLoad$ = new Subject<IForOfState>();
155
+
156
+ constructor() {
157
+ this.dataPreLoad$.pipe(
158
+ debounceTime(150),
159
+ takeUntilDestroyed(this.destroyRef)
160
+ ).subscribe(event => {
161
+ // NOTE: The first chunkSize will always be 0 — use a reasonable default
162
+ const chunkSize = event.chunkSize || 15;
163
+ this.loadData(event.startIndex, chunkSize);
164
+ });
165
+
166
+ this.loadData(0, 15);
167
+ }
168
+
169
+ onDataPreLoad(event: IForOfState) {
170
+ this.dataPreLoad$.next(event);
171
+ }
172
+
173
+ onSortingDone(event: ISortingEventArgs) {
174
+ this.currentSort = this.gridRef().sortingExpressions;
175
+ this.loadData(0, 15);
176
+ }
177
+
178
+ onFilteringExpressionsTreeChange() {
179
+ this.currentFilter = this.gridRef().filteringExpressionsTree;
180
+ this.loadData(0, 15);
181
+ }
182
+
183
+ private loadData(skip: number, take: number) {
184
+ this.isLoading.set(true);
185
+ this.dataService.getOrders({
186
+ skip,
187
+ take,
188
+ sort: this.currentSort,
189
+ filter: this.currentFilter
190
+ }).subscribe(result => {
191
+ this.data.set(result.data);
192
+ this.totalCount.set(result.total);
193
+ this.isLoading.set(false);
194
+ });
195
+ }
196
+ }
197
+ ```
198
+
199
+ ```html
200
+ <igx-grid #grid
201
+ [data]="data()"
202
+ [primaryKey]="'orderId'"
203
+ [totalItemCount]="totalCount()"
204
+ [isLoading]="isLoading()"
205
+ [autoGenerate]="false"
206
+ [allowFiltering]="true"
207
+ [filterMode]="'excelStyleFilter'"
208
+ [sortStrategy]="noopSort"
209
+ [filterStrategy]="noopFilter"
210
+ (dataPreLoad)="onDataPreLoad($event)"
211
+ (sortingDone)="onSortingDone($event)"
212
+ (filteringExpressionsTreeChange)="onFilteringExpressionsTreeChange()"
213
+ height="600px">
214
+
215
+ <igx-column field="orderId" header="Order ID" [sortable]="true"></igx-column>
216
+ <igx-column field="customer" header="Customer" [sortable]="true" [filterable]="true"></igx-column>
217
+ <igx-column field="orderDate" header="Date" dataType="date" [sortable]="true" [filterable]="true"></igx-column>
218
+ <igx-column field="amount" header="Amount" dataType="number" [sortable]="true" [filterable]="true"></igx-column>
219
+ <igx-column field="status" header="Status" [filterable]="true"></igx-column>
220
+ </igx-grid>
221
+ ```
222
+
223
+ > **IMPORTANT**: `[sortStrategy]="noopSort"` and `[filterStrategy]="noopFilter"` prevent the grid from applying sort/filter operations client-side. The grid still fires events (allowing you to send them to the server), but the local data remains untouched until you replace it.
224
+
225
+ ### Excel-Style Filtering with Remote Unique Values
226
+
227
+ When using Excel-style filtering with remote data, provide a strategy to fetch unique column values from the server:
228
+
229
+ ```typescript
230
+ // Tell the grid how to load unique values for Excel-style filter lists
231
+ uniqueValuesStrategy = (column: any, tree: any, done: (values: any[]) => void) => {
232
+ this.dataService.getUniqueValues(column.field).subscribe(values => done(values));
233
+ };
234
+ ```
235
+
236
+ ```html
237
+ <igx-grid #grid
238
+ [data]="data()"
239
+ [uniqueColumnValuesStrategy]="uniqueValuesStrategy"
240
+ [filterMode]="'excelStyleFilter'"
241
+ [allowFiltering]="true">
242
+ </igx-grid>
243
+ ```
244
+
245
+ ### Remote Data Service Example
246
+
247
+ ```typescript
248
+ import { Injectable, inject } from '@angular/core';
249
+ import { HttpClient, HttpParams } from '@angular/common/http';
250
+ import { Observable } from 'rxjs';
251
+
252
+ export interface RemoteDataResult<T> {
253
+ data: T[];
254
+ total: number;
255
+ }
256
+
257
+ @Injectable({ providedIn: 'root' })
258
+ export class OrderService {
259
+ private http = inject(HttpClient);
260
+ private apiUrl = '/api/orders';
261
+
262
+ getOrders(params: {
263
+ skip: number;
264
+ take: number;
265
+ sort?: any[];
266
+ filter?: any;
267
+ }): Observable<RemoteDataResult<Order>> {
268
+ let httpParams = new HttpParams()
269
+ .set('skip', params.skip)
270
+ .set('take', params.take);
271
+
272
+ if (params.sort?.length) {
273
+ httpParams = httpParams.set('sort', JSON.stringify(params.sort));
274
+ }
275
+ if (params.filter) {
276
+ httpParams = httpParams.set('filter', JSON.stringify(params.filter));
277
+ }
278
+
279
+ return this.http.get<RemoteDataResult<Order>>(this.apiUrl, { params: httpParams });
280
+ }
281
+ }
282
+ ```
283
+
284
+ ### Key Points for Remote Data
285
+
286
+ 1. **Set `[totalItemCount]`** — the grid needs the total record count for correct virtual scrollbar sizing
287
+ 2. **Use `[isLoading]`** — shows a loading indicator while data is being fetched
288
+ 3. **Apply `NoopSortingStrategy` and `NoopFilteringStrategy`** — prevents the grid from performing client-side sorting/filtering, so the server results are displayed as-is
289
+ 4. **Listen to `(dataPreLoad)`** — fires when the user scrolls and the grid needs more rows; provides `startIndex` and `chunkSize` (first `chunkSize` will be 0 — use a fallback)
290
+ 5. **Listen to `(sortingDone)` and `(filteringExpressionsTreeChange)`** — reset to the beginning and re-fetch with new parameters; `filteringExpressionsTreeChange` is the grid-level output that reflects the complete filter state (unlike the column-level `filteringDone`)
291
+ 6. **Track current sort/filter state** — store them so every `loadData` call includes the active criteria
292
+ 7. **Debounce `(dataPreLoad)`** — use `debounceTime` to avoid flooding the server during fast scrolling
293
+ 8. **Use `[uniqueColumnValuesStrategy]`** — when using Excel-style filtering, supply a callback to load unique column values from the server
294
+
295
+ ## Virtualization
296
+
297
+ ### How It Works
298
+
299
+ All Ignite UI grids use **row and column virtualization** by default. Only the visible rows and columns are rendered in the DOM, enabling smooth scrolling through millions of records.
300
+
301
+ ### Requirements
302
+
303
+ - Set a fixed `height` on the grid (e.g., `height="600px"`)
304
+ - No additional configuration is needed — virtualization is automatic
305
+ - Do **not** wrap the grid in a virtual scroll container
306
+
307
+ ### Remote Virtualization
308
+
309
+ For datasets too large to load entirely, combine virtualization with remote data:
310
+
311
+ ```html
312
+ <igx-grid #grid
313
+ [data]="data()"
314
+ [totalItemCount]="totalCount()"
315
+ (dataPreLoad)="onDataPreLoad($event)"
316
+ height="600px">
317
+ </igx-grid>
318
+ ```
319
+
320
+ The `(dataPreLoad)` event fires with an `IForOfState` containing:
321
+ - `startIndex` — the first visible row index
322
+ - `chunkSize` — number of rows the grid needs
323
+
324
+ ## Multi-Grid Coordination
325
+
326
+ ### Master-Detail Filtering
327
+
328
+ When using a master grid to drive a detail grid:
329
+
330
+ ```typescript
331
+ export class MasterDetailComponent {
332
+ masterGrid = viewChild.required<IgxGridComponent>('masterGrid');
333
+ orders = signal<Order[]>([]);
334
+ selectedCustomer = signal<Customer | null>(null);
335
+ customerOrders = signal<Order[]>([]);
336
+
337
+ onRowSelectionChanging(event: IRowSelectionEventArgs) {
338
+ const selectedId = event.newSelection[0];
339
+ const customer = this.customers().find(c => c.id === selectedId);
340
+ this.selectedCustomer.set(customer ?? null);
341
+
342
+ if (customer) {
343
+ this.dataService.getOrdersByCustomer(customer.id).subscribe(orders => {
344
+ this.customerOrders.set(orders);
345
+ });
346
+ }
347
+ }
348
+ }
349
+ ```
350
+
351
+ ```html
352
+ <igx-grid #masterGrid
353
+ [data]="customers()"
354
+ [primaryKey]="'id'"
355
+ [rowSelection]="'single'"
356
+ (rowSelectionChanging)="onRowSelectionChanging($event)"
357
+ height="300px">
358
+ <igx-column field="name" header="Customer"></igx-column>
359
+ </igx-grid>
360
+
361
+ <igx-grid
362
+ [data]="customerOrders()"
363
+ [primaryKey]="'orderId'"
364
+ height="300px">
365
+ <igx-column field="orderId" header="Order"></igx-column>
366
+ <igx-column field="amount" header="Amount" dataType="number"></igx-column>
367
+ </igx-grid>
368
+ ```
369
+
370
+ ## Key Rules
371
+
372
+ 1. **Remote data requires `[totalItemCount]`** — without it, the virtual scrollbar won't size correctly
373
+ 2. **Remote data requires noop strategies** — apply `NoopSortingStrategy` and `NoopFilteringStrategy` to disable client-side operations when the server handles them
374
+ 3. **Track sort/filter state for remote operations** — store current expressions and include them in every server request
375
+ 4. **Debounce rapid virtual scroll** — use `debounceTime` on `(dataPreLoad)` to avoid flooding the server
376
+ 5. **Virtualization is automatic** — don't wrap grids in virtual scroll containers; just set a fixed `height`
377
+ 6. **Use the correct component type for `viewChild`** — `IgxGridComponent`, `IgxTreeGridComponent`, `IgxHierarchicalGridComponent`, or `IgxPivotGridComponent`
378
+ 7. **Import the correct directives/components** — `IGX_GRID_DIRECTIVES`, `IGX_TREE_GRID_DIRECTIVES`, `IGX_HIERARCHICAL_GRID_DIRECTIVES`, or `IGX_PIVOT_GRID_DIRECTIVES`
379
+ 8. **Use signals for data** — `[data]="myData()"` with `signal<T[]>([])`
380
+
381
+ ## See Also
382
+
383
+ - [`data-operations.md`](./data-operations.md) — Sorting, filtering, grouping, and canonical grid import patterns
384
+ - [`editing.md`](./editing.md) — Cell editing, row editing, batch editing, validation, summaries
385
+ - [`state.md`](./state.md) — State persistence, Tree Grid / Hierarchical Grid / Pivot Grid / Grid Lite data operations
386
+ - [`structure.md`](./structure.md) — Grid structure, column configuration, templates, layout, selection
387
+ - [`../../igniteui-angular-components/SKILL.md`](../../igniteui-angular-components/SKILL.md) — Non-grid Ignite UI components
388
+ - [`../../igniteui-angular-theming/SKILL.md`](../../igniteui-angular-theming/SKILL.md) — Theming & Styling