@igniteui/angular-templates 21.1.14100-alpha.2 → 21.1.14100-alpha.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/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-components/SKILL.md +68 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-components/references/charts.md +457 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-components/references/data-display.md +360 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-components/references/directives.md +272 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-components/references/feedback.md +149 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-components/references/form-controls.md +313 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-components/references/layout-manager.md +420 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-components/references/layout.md +225 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-components/references/setup.md +166 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-grids/SKILL.md +110 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-grids/references/data-operations.md +445 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-grids/references/editing.md +491 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-grids/references/features.md +234 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-grids/references/paging-remote.md +397 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-grids/references/state.md +314 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-grids/references/structure.md +299 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-grids/references/types.md +507 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-theming/SKILL.md +439 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-theming/references/common-patterns.md +45 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-theming/references/contributing.md +471 -0
- package/igx-ts/projects/_base/files/__dot__claude/skills/igniteui-angular-theming/references/mcp-setup.md +77 -0
- package/igx-ts/projects/_base/files/__dot__vscode/mcp.json +2 -2
- package/package.json +2 -2
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Grid Features — Grouping, Summaries, Toolbar, Export, Row Drag & More
|
|
2
|
+
|
|
3
|
+
> **Part of the [`igniteui-angular-grids`](../SKILL.md) skill hub.**
|
|
4
|
+
> For grid setup, column config, sorting, filtering, selection — see [`structure.md`](./structure.md).
|
|
5
|
+
> For Tree Grid, Hierarchical Grid, Grid Lite, Pivot Grid specifics — see [`types.md`](./types.md).
|
|
6
|
+
> For full editing coverage (cell/row/batch) — see [`editing.md`](./editing.md).
|
|
7
|
+
|
|
8
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
- [Editing](#editing)
|
|
11
|
+
- [Grouping (Grid only)](#grouping-grid-only)
|
|
12
|
+
- [Summaries](#summaries)
|
|
13
|
+
- [Cell Merging](#cell-merging)
|
|
14
|
+
- [Toolbar](#toolbar)
|
|
15
|
+
- [Export](#export)
|
|
16
|
+
- [Virtualization & Performance](#virtualization--performance)
|
|
17
|
+
- [Row Drag](#row-drag)
|
|
18
|
+
- [Action Strip](#action-strip)
|
|
19
|
+
- [Master-Detail (Grid only)](#master-detail-grid-only)
|
|
20
|
+
- [Clipboard](#clipboard)
|
|
21
|
+
- [Key Rules](#key-rules)
|
|
22
|
+
|
|
23
|
+
## Editing
|
|
24
|
+
|
|
25
|
+
> **Full editing coverage is in [`editing.md`](./editing.md)**, which includes cell editing, row editing, batch editing with transactions, row adding/deleting, validation, and summaries. Use that reference for any editing task.
|
|
26
|
+
|
|
27
|
+
Quick reference:
|
|
28
|
+
|
|
29
|
+
| Mode | Key properties |
|
|
30
|
+
|---|---|
|
|
31
|
+
| **Cell editing** | `[editable]="true"` on columns + `(cellEditDone)` |
|
|
32
|
+
| **Row editing** (recommended default) | `[rowEditable]="true"` + `[editable]="true"` on columns + `(rowEditDone)` |
|
|
33
|
+
| **Batch editing** | `[batchEditing]="true"` + `[rowEditable]="true"` + `transactions.commit(data)` |
|
|
34
|
+
|
|
35
|
+
## Grouping (Grid only)
|
|
36
|
+
|
|
37
|
+
> **Docs:** [Group By](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/groupby)
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<igx-grid [data]="data()" [groupsExpanded]="true">
|
|
41
|
+
<igx-column field="category" [groupable]="true"></igx-column>
|
|
42
|
+
|
|
43
|
+
<!-- Custom group row template -->
|
|
44
|
+
<ng-template igxGroupByRow let-groupRow>
|
|
45
|
+
{{ groupRow.expression.fieldName }}: {{ groupRow.value }} ({{ groupRow.records.length }} items)
|
|
46
|
+
</ng-template>
|
|
47
|
+
</igx-grid>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Programmatic:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
this.gridRef().groupBy({ fieldName: 'category', dir: SortingDirection.Asc });
|
|
54
|
+
this.gridRef().clearGrouping('category');
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
For advanced programmatic grouping patterns — see [`data-operations.md`](./data-operations.md).
|
|
58
|
+
|
|
59
|
+
## Summaries
|
|
60
|
+
|
|
61
|
+
> **Full summaries coverage — built-in summaries, custom summary operands, and summaries with grouping — is in [`editing.md`](./editing.md#summaries).**
|
|
62
|
+
>
|
|
63
|
+
> Quick reference: enable per-column summaries with `[hasSummary]="true"` on an `igx-column`. Default operands: **number** → Count/Min/Max/Sum/Average; **date** → Count/Earliest/Latest; **string/boolean** → Count.
|
|
64
|
+
|
|
65
|
+
## Cell Merging
|
|
66
|
+
|
|
67
|
+
Merge adjacent cells with equal values:
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<igx-column field="category" [merge]="true"></igx-column>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Or apply a custom merge strategy:
|
|
74
|
+
|
|
75
|
+
```html
|
|
76
|
+
<igx-column field="price" [merge]="true" [mergeStrategy]="priceRangeMerge"></igx-column>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { IGridMergeStrategy } from 'igniteui-angular/core';
|
|
81
|
+
// import { IGridMergeStrategy } from '@infragistics/igniteui-angular/core'; for licensed package
|
|
82
|
+
|
|
83
|
+
priceRangeMerge: IGridMergeStrategy = {
|
|
84
|
+
shouldMerge(prevCell, curCell) {
|
|
85
|
+
return Math.abs(prevCell.value - curCell.value) < 10;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Toolbar
|
|
91
|
+
|
|
92
|
+
> **Docs:** [Toolbar](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/toolbar)
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { IgxGridToolbarComponent } from 'igniteui-angular/grids/core';
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```html
|
|
99
|
+
<igx-grid [data]="data()">
|
|
100
|
+
<igx-grid-toolbar>
|
|
101
|
+
<igx-grid-toolbar-title>Products</igx-grid-toolbar-title>
|
|
102
|
+
<igx-grid-toolbar-actions>
|
|
103
|
+
<igx-grid-toolbar-hiding></igx-grid-toolbar-hiding>
|
|
104
|
+
<igx-grid-toolbar-pinning></igx-grid-toolbar-pinning>
|
|
105
|
+
<igx-grid-toolbar-exporter></igx-grid-toolbar-exporter>
|
|
106
|
+
<igx-grid-toolbar-advanced-filtering></igx-grid-toolbar-advanced-filtering>
|
|
107
|
+
</igx-grid-toolbar-actions>
|
|
108
|
+
</igx-grid-toolbar>
|
|
109
|
+
|
|
110
|
+
<igx-column field="name"></igx-column>
|
|
111
|
+
</igx-grid>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Export
|
|
115
|
+
|
|
116
|
+
### Excel Export
|
|
117
|
+
|
|
118
|
+
> **Docs:** [Excel Export](https://www.infragistics.com/products/ignite-ui-angular/angular/components/exporter-excel)
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { IgxExcelExporterService, IgxExcelExporterOptions } from 'igniteui-angular/grids/core';
|
|
122
|
+
|
|
123
|
+
export class MyComponent {
|
|
124
|
+
private excelExporter = inject(IgxExcelExporterService);
|
|
125
|
+
|
|
126
|
+
exportToExcel() {
|
|
127
|
+
this.excelExporter.exportData(this.data(), new IgxExcelExporterOptions('export'));
|
|
128
|
+
// Or export the grid (respects filtering/sorting)
|
|
129
|
+
this.excelExporter.export(this.grid, new IgxExcelExporterOptions('export'));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### CSV Export
|
|
135
|
+
|
|
136
|
+
> **Docs:** [CSV Export](https://www.infragistics.com/products/ignite-ui-angular/angular/components/exporter-csv)
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { IgxCsvExporterService, IgxCsvExporterOptions, CsvFileTypes } from 'igniteui-angular/grids/core';
|
|
140
|
+
|
|
141
|
+
export class MyComponent {
|
|
142
|
+
private csvExporter = inject(IgxCsvExporterService);
|
|
143
|
+
|
|
144
|
+
exportToCsv() {
|
|
145
|
+
this.csvExporter.export(this.grid, new IgxCsvExporterOptions('export', CsvFileTypes.CSV));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Virtualization & Performance
|
|
151
|
+
|
|
152
|
+
Grids use virtualization by default for both rows and columns — no setup needed. For remote data/paging:
|
|
153
|
+
|
|
154
|
+
```html
|
|
155
|
+
<igx-grid [data]="data()" [totalItemCount]="totalCount" (dataPreLoad)="onDataPreLoad($event)">
|
|
156
|
+
</igx-grid>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
For full remote virtualization patterns — see [`paging-remote.md`](./paging-remote.md).
|
|
160
|
+
|
|
161
|
+
## Row Drag
|
|
162
|
+
|
|
163
|
+
> **Docs:** [Row Drag](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/row-drag)
|
|
164
|
+
|
|
165
|
+
```html
|
|
166
|
+
<igx-grid [rowDraggable]="true" (rowDragStart)="onDragStart($event)" (rowDragEnd)="onDragEnd($event)">
|
|
167
|
+
<ng-template igxRowDragGhost let-dragData>
|
|
168
|
+
<span>Moving {{ dragData.dragData.name }}</span>
|
|
169
|
+
</ng-template>
|
|
170
|
+
</igx-grid>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Action Strip
|
|
174
|
+
|
|
175
|
+
> **Docs:** [Action Strip](https://www.infragistics.com/products/ignite-ui-angular/angular/components/action-strip)
|
|
176
|
+
|
|
177
|
+
Overlay actions on a row:
|
|
178
|
+
|
|
179
|
+
```html
|
|
180
|
+
<igx-grid [data]="data()">
|
|
181
|
+
<igx-action-strip>
|
|
182
|
+
<igx-grid-editing-actions [addRow]="true"></igx-grid-editing-actions>
|
|
183
|
+
<igx-grid-pinning-actions></igx-grid-pinning-actions>
|
|
184
|
+
</igx-action-strip>
|
|
185
|
+
<igx-column field="name"></igx-column>
|
|
186
|
+
</igx-grid>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Master-Detail (Grid only)
|
|
190
|
+
|
|
191
|
+
> **Docs:** [Master-Detail](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/master-detail)
|
|
192
|
+
|
|
193
|
+
Expand rows to show arbitrary detail content:
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<igx-grid [data]="orders()" [primaryKey]="'orderId'">
|
|
197
|
+
<igx-column field="orderId"></igx-column>
|
|
198
|
+
<igx-column field="customer"></igx-column>
|
|
199
|
+
|
|
200
|
+
<ng-template igxGridDetail let-dataItem>
|
|
201
|
+
<div class="detail-container">
|
|
202
|
+
<h4>Order Items for {{ dataItem.customer }}</h4>
|
|
203
|
+
<igx-grid [data]="dataItem.items" [autoGenerate]="true" height="200px">
|
|
204
|
+
</igx-grid>
|
|
205
|
+
</div>
|
|
206
|
+
</ng-template>
|
|
207
|
+
</igx-grid>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Clipboard
|
|
211
|
+
|
|
212
|
+
Grids support copy to clipboard by default. Configure via:
|
|
213
|
+
|
|
214
|
+
```html
|
|
215
|
+
<igx-grid [clipboardOptions]="{ enabled: true, copyHeaders: true, copyFormatters: true, separator: '\t' }">
|
|
216
|
+
</igx-grid>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Key Rules
|
|
220
|
+
|
|
221
|
+
1. **Cancelable events** — use `event.cancel = true` in `(rowEdit)`, `(cellEdit)`, `(sorting)`, `(filtering)` to prevent the action
|
|
222
|
+
2. **Use signals** for data binding — `[data]="myData()"` with `signal<T[]>([])`
|
|
223
|
+
3. **Virtualization is automatic** — don't wrap grids in virtual scroll containers
|
|
224
|
+
4. **GroupBy is Flat Grid only** — Tree Grid uses hierarchy, Hierarchical Grid uses row islands, Pivot Grid uses dimensions
|
|
225
|
+
|
|
226
|
+
## See Also
|
|
227
|
+
|
|
228
|
+
- [`structure.md`](./structure.md) — Column config, sorting UI, filtering UI, selection
|
|
229
|
+
- [`types.md`](./types.md) — Tree Grid, Hierarchical Grid, Grid Lite, Pivot Grid specifics
|
|
230
|
+
- [`data-operations.md`](./data-operations.md) — Programmatic sorting, filtering, grouping
|
|
231
|
+
- [`paging-remote.md`](./paging-remote.md) — Paging, remote data operations, virtualization
|
|
232
|
+
- [`editing.md`](./editing.md) — Cell editing, row editing, batch editing, validation, summaries
|
|
233
|
+
- [`state.md`](./state.md) — State persistence
|
|
234
|
+
- [`../../igniteui-angular-theming/SKILL.md`](../../igniteui-angular-theming/SKILL.md) — Grid styling and theming
|
|
@@ -0,0 +1,397 @@
|
|
|
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
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
- [Paging](#paging)
|
|
11
|
+
- [Remote Data Operations](#remote-data-operations)
|
|
12
|
+
- [Virtualization](#virtualization)
|
|
13
|
+
- [Multi-Grid Coordination](#multi-grid-coordination)
|
|
14
|
+
- [Key Rules](#key-rules)
|
|
15
|
+
|
|
16
|
+
## Paging
|
|
17
|
+
|
|
18
|
+
> **Docs:** [Paging — Remote Paging](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/paging#remote-paging) (substitute URL prefix per grid type)
|
|
19
|
+
|
|
20
|
+
### Using the Paginator Component
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<igx-grid #grid
|
|
24
|
+
[data]="data()"
|
|
25
|
+
[primaryKey]="'id'"
|
|
26
|
+
height="600px">
|
|
27
|
+
<igx-column field="name"></igx-column>
|
|
28
|
+
<igx-column field="amount" dataType="number"></igx-column>
|
|
29
|
+
|
|
30
|
+
<igx-paginator
|
|
31
|
+
[perPage]="15"
|
|
32
|
+
[selectOptions]="[10, 15, 25, 50]"
|
|
33
|
+
[displayDensity]="'comfortable'">
|
|
34
|
+
</igx-paginator>
|
|
35
|
+
</igx-grid>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Programmatic Paging
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// Navigate pages
|
|
42
|
+
this.gridRef().paginator.page = 3;
|
|
43
|
+
this.gridRef().paginator.nextPage();
|
|
44
|
+
this.gridRef().paginator.previousPage();
|
|
45
|
+
this.gridRef().paginator.paginate(0); // go to first page
|
|
46
|
+
|
|
47
|
+
// Change page size
|
|
48
|
+
this.gridRef().paginator.perPage = 25;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Paging Events
|
|
52
|
+
|
|
53
|
+
| Event | Description |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `(paging)` | Fires before page changes (cancelable) |
|
|
56
|
+
| `(pagingDone)` | Fires after page has changed |
|
|
57
|
+
| `(perPageChange)` | Fires when page size changes |
|
|
58
|
+
|
|
59
|
+
### Remote Paging
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { GridPagingMode } from 'igniteui-angular/grids/core';
|
|
63
|
+
import { IPageEventArgs } from 'igniteui-angular/paginator';
|
|
64
|
+
|
|
65
|
+
export class RemotePagingComponent {
|
|
66
|
+
data = signal<Product[]>([]);
|
|
67
|
+
totalCount = signal(0);
|
|
68
|
+
perPage = signal(15);
|
|
69
|
+
pagingMode = GridPagingMode.Remote;
|
|
70
|
+
|
|
71
|
+
gridRef = viewChild.required<IgxGridComponent>('grid');
|
|
72
|
+
private dataService = inject(ProductService);
|
|
73
|
+
|
|
74
|
+
constructor() {
|
|
75
|
+
this.loadPage(0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
onPagingDone(event: IPageEventArgs) {
|
|
79
|
+
this.loadPage(event.current);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onPerPageChange(perPage: number) {
|
|
83
|
+
this.perPage.set(perPage);
|
|
84
|
+
this.loadPage(0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private loadPage(pageIndex: number) {
|
|
88
|
+
const skip = pageIndex * this.perPage();
|
|
89
|
+
this.dataService.getProducts({ skip, take: this.perPage() }).subscribe(result => {
|
|
90
|
+
this.data.set(result.data);
|
|
91
|
+
this.totalCount.set(result.totalCount);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<igx-grid #grid
|
|
99
|
+
[data]="data()"
|
|
100
|
+
[primaryKey]="'id'"
|
|
101
|
+
[pagingMode]="pagingMode"
|
|
102
|
+
height="600px">
|
|
103
|
+
<igx-column field="name"></igx-column>
|
|
104
|
+
<igx-column field="price" dataType="number"></igx-column>
|
|
105
|
+
|
|
106
|
+
<igx-paginator
|
|
107
|
+
[perPage]="perPage()"
|
|
108
|
+
[totalRecords]="totalCount()"
|
|
109
|
+
(pagingDone)="onPagingDone($event)"
|
|
110
|
+
(perPageChange)="onPerPageChange($event)">
|
|
111
|
+
</igx-paginator>
|
|
112
|
+
</igx-grid>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Remote Data Operations
|
|
116
|
+
|
|
117
|
+
> **Docs:** [Remote Data Operations](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/remote-data-operations) (substitute URL prefix per grid type)
|
|
118
|
+
|
|
119
|
+
### The Problem
|
|
120
|
+
|
|
121
|
+
Grids perform sorting, filtering, and paging **client-side** by default. For large datasets, you must intercept these operations and delegate them to the server.
|
|
122
|
+
|
|
123
|
+
### Complete Remote Data Pattern
|
|
124
|
+
|
|
125
|
+
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:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Component, ChangeDetectionStrategy, signal, viewChild, inject, DestroyRef } from '@angular/core';
|
|
129
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
130
|
+
import { IgxGridComponent, IGX_GRID_DIRECTIVES } from 'igniteui-angular/grids/grid';
|
|
131
|
+
import {
|
|
132
|
+
IFilteringExpressionsTree,
|
|
133
|
+
NoopSortingStrategy,
|
|
134
|
+
NoopFilteringStrategy
|
|
135
|
+
} from 'igniteui-angular/core';
|
|
136
|
+
import { IForOfState } from 'igniteui-angular/directives';
|
|
137
|
+
import { ISortingEventArgs } from 'igniteui-angular/grids/core';
|
|
138
|
+
import { debounceTime, Subject } from 'rxjs';
|
|
139
|
+
|
|
140
|
+
@Component({
|
|
141
|
+
selector: 'app-remote-grid',
|
|
142
|
+
imports: [IGX_GRID_DIRECTIVES],
|
|
143
|
+
templateUrl: './remote-grid.component.html',
|
|
144
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
145
|
+
})
|
|
146
|
+
export class RemoteGridComponent {
|
|
147
|
+
data = signal<Order[]>([]);
|
|
148
|
+
totalCount = signal(0);
|
|
149
|
+
isLoading = signal(false);
|
|
150
|
+
|
|
151
|
+
// Noop strategies — disable built-in client-side sort/filter
|
|
152
|
+
noopSort = NoopSortingStrategy.instance();
|
|
153
|
+
noopFilter = NoopFilteringStrategy.instance();
|
|
154
|
+
|
|
155
|
+
gridRef = viewChild.required<IgxGridComponent>('grid');
|
|
156
|
+
private dataService = inject(OrderService);
|
|
157
|
+
private destroyRef = inject(DestroyRef);
|
|
158
|
+
|
|
159
|
+
private currentSort: ISortingEventArgs[] | undefined;
|
|
160
|
+
private currentFilter: IFilteringExpressionsTree | undefined;
|
|
161
|
+
|
|
162
|
+
// Debounce rapid dataPreLoad events during fast scrolling
|
|
163
|
+
private dataPreLoad$ = new Subject<IForOfState>();
|
|
164
|
+
|
|
165
|
+
constructor() {
|
|
166
|
+
this.dataPreLoad$.pipe(
|
|
167
|
+
debounceTime(150),
|
|
168
|
+
takeUntilDestroyed(this.destroyRef)
|
|
169
|
+
).subscribe(event => {
|
|
170
|
+
// NOTE: The first chunkSize will always be 0 — use a reasonable default
|
|
171
|
+
const chunkSize = event.chunkSize || 15;
|
|
172
|
+
this.loadData(event.startIndex, chunkSize);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
this.loadData(0, 15);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
onDataPreLoad(event: IForOfState) {
|
|
179
|
+
this.dataPreLoad$.next(event);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
onSortingDone(event: ISortingEventArgs) {
|
|
183
|
+
this.currentSort = this.gridRef().sortingExpressions;
|
|
184
|
+
this.loadData(0, 15);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
onFilteringExpressionsTreeChange() {
|
|
188
|
+
this.currentFilter = this.gridRef().filteringExpressionsTree;
|
|
189
|
+
this.loadData(0, 15);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private loadData(skip: number, take: number) {
|
|
193
|
+
this.isLoading.set(true);
|
|
194
|
+
this.dataService.getOrders({
|
|
195
|
+
skip,
|
|
196
|
+
take,
|
|
197
|
+
sort: this.currentSort,
|
|
198
|
+
filter: this.currentFilter
|
|
199
|
+
}).subscribe(result => {
|
|
200
|
+
this.data.set(result.data);
|
|
201
|
+
this.totalCount.set(result.total);
|
|
202
|
+
this.isLoading.set(false);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
```html
|
|
209
|
+
<igx-grid #grid
|
|
210
|
+
[data]="data()"
|
|
211
|
+
[primaryKey]="'orderId'"
|
|
212
|
+
[totalItemCount]="totalCount()"
|
|
213
|
+
[isLoading]="isLoading()"
|
|
214
|
+
[autoGenerate]="false"
|
|
215
|
+
[allowFiltering]="true"
|
|
216
|
+
[filterMode]="'excelStyleFilter'"
|
|
217
|
+
[sortStrategy]="noopSort"
|
|
218
|
+
[filterStrategy]="noopFilter"
|
|
219
|
+
(dataPreLoad)="onDataPreLoad($event)"
|
|
220
|
+
(sortingDone)="onSortingDone($event)"
|
|
221
|
+
(filteringExpressionsTreeChange)="onFilteringExpressionsTreeChange()"
|
|
222
|
+
height="600px">
|
|
223
|
+
|
|
224
|
+
<igx-column field="orderId" header="Order ID" [sortable]="true"></igx-column>
|
|
225
|
+
<igx-column field="customer" header="Customer" [sortable]="true" [filterable]="true"></igx-column>
|
|
226
|
+
<igx-column field="orderDate" header="Date" dataType="date" [sortable]="true" [filterable]="true"></igx-column>
|
|
227
|
+
<igx-column field="amount" header="Amount" dataType="number" [sortable]="true" [filterable]="true"></igx-column>
|
|
228
|
+
<igx-column field="status" header="Status" [filterable]="true"></igx-column>
|
|
229
|
+
</igx-grid>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
> **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.
|
|
233
|
+
|
|
234
|
+
### Excel-Style Filtering with Remote Unique Values
|
|
235
|
+
|
|
236
|
+
When using Excel-style filtering with remote data, provide a strategy to fetch unique column values from the server:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// Tell the grid how to load unique values for Excel-style filter lists
|
|
240
|
+
uniqueValuesStrategy = (column: any, tree: any, done: (values: any[]) => void) => {
|
|
241
|
+
this.dataService.getUniqueValues(column.field).subscribe(values => done(values));
|
|
242
|
+
};
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
```html
|
|
246
|
+
<igx-grid #grid
|
|
247
|
+
[data]="data()"
|
|
248
|
+
[uniqueColumnValuesStrategy]="uniqueValuesStrategy"
|
|
249
|
+
[filterMode]="'excelStyleFilter'"
|
|
250
|
+
[allowFiltering]="true">
|
|
251
|
+
</igx-grid>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Remote Data Service Example
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { Injectable, inject } from '@angular/core';
|
|
258
|
+
import { HttpClient, HttpParams } from '@angular/common/http';
|
|
259
|
+
import { Observable } from 'rxjs';
|
|
260
|
+
|
|
261
|
+
export interface RemoteDataResult<T> {
|
|
262
|
+
data: T[];
|
|
263
|
+
total: number;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
@Injectable({ providedIn: 'root' })
|
|
267
|
+
export class OrderService {
|
|
268
|
+
private http = inject(HttpClient);
|
|
269
|
+
private apiUrl = '/api/orders';
|
|
270
|
+
|
|
271
|
+
getOrders(params: {
|
|
272
|
+
skip: number;
|
|
273
|
+
take: number;
|
|
274
|
+
sort?: any[];
|
|
275
|
+
filter?: any;
|
|
276
|
+
}): Observable<RemoteDataResult<Order>> {
|
|
277
|
+
let httpParams = new HttpParams()
|
|
278
|
+
.set('skip', params.skip)
|
|
279
|
+
.set('take', params.take);
|
|
280
|
+
|
|
281
|
+
if (params.sort?.length) {
|
|
282
|
+
httpParams = httpParams.set('sort', JSON.stringify(params.sort));
|
|
283
|
+
}
|
|
284
|
+
if (params.filter) {
|
|
285
|
+
httpParams = httpParams.set('filter', JSON.stringify(params.filter));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return this.http.get<RemoteDataResult<Order>>(this.apiUrl, { params: httpParams });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Key Points for Remote Data
|
|
294
|
+
|
|
295
|
+
1. **Set `[totalItemCount]`** — the grid needs the total record count for correct virtual scrollbar sizing
|
|
296
|
+
2. **Use `[isLoading]`** — shows a loading indicator while data is being fetched
|
|
297
|
+
3. **Apply `NoopSortingStrategy` and `NoopFilteringStrategy`** — prevents the grid from performing client-side sorting/filtering, so the server results are displayed as-is
|
|
298
|
+
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)
|
|
299
|
+
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`)
|
|
300
|
+
6. **Track current sort/filter state** — store them so every `loadData` call includes the active criteria
|
|
301
|
+
7. **Debounce `(dataPreLoad)`** — use `debounceTime` to avoid flooding the server during fast scrolling
|
|
302
|
+
8. **Use `[uniqueColumnValuesStrategy]`** — when using Excel-style filtering, supply a callback to load unique column values from the server
|
|
303
|
+
|
|
304
|
+
## Virtualization
|
|
305
|
+
|
|
306
|
+
### How It Works
|
|
307
|
+
|
|
308
|
+
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.
|
|
309
|
+
|
|
310
|
+
### Requirements
|
|
311
|
+
|
|
312
|
+
- Set a fixed `height` on the grid (e.g., `height="600px"`)
|
|
313
|
+
- No additional configuration is needed — virtualization is automatic
|
|
314
|
+
- Do **not** wrap the grid in a virtual scroll container
|
|
315
|
+
|
|
316
|
+
### Remote Virtualization
|
|
317
|
+
|
|
318
|
+
For datasets too large to load entirely, combine virtualization with remote data:
|
|
319
|
+
|
|
320
|
+
```html
|
|
321
|
+
<igx-grid #grid
|
|
322
|
+
[data]="data()"
|
|
323
|
+
[totalItemCount]="totalCount()"
|
|
324
|
+
(dataPreLoad)="onDataPreLoad($event)"
|
|
325
|
+
height="600px">
|
|
326
|
+
</igx-grid>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
The `(dataPreLoad)` event fires with an `IForOfState` containing:
|
|
330
|
+
- `startIndex` — the first visible row index
|
|
331
|
+
- `chunkSize` — number of rows the grid needs
|
|
332
|
+
|
|
333
|
+
## Multi-Grid Coordination
|
|
334
|
+
|
|
335
|
+
### Master-Detail Filtering
|
|
336
|
+
|
|
337
|
+
When using a master grid to drive a detail grid:
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
export class MasterDetailComponent {
|
|
341
|
+
masterGrid = viewChild.required<IgxGridComponent>('masterGrid');
|
|
342
|
+
orders = signal<Order[]>([]);
|
|
343
|
+
selectedCustomer = signal<Customer | null>(null);
|
|
344
|
+
customerOrders = signal<Order[]>([]);
|
|
345
|
+
|
|
346
|
+
onRowSelectionChanging(event: IRowSelectionEventArgs) {
|
|
347
|
+
const selectedId = event.newSelection[0];
|
|
348
|
+
const customer = this.customers().find(c => c.id === selectedId);
|
|
349
|
+
this.selectedCustomer.set(customer ?? null);
|
|
350
|
+
|
|
351
|
+
if (customer) {
|
|
352
|
+
this.dataService.getOrdersByCustomer(customer.id).subscribe(orders => {
|
|
353
|
+
this.customerOrders.set(orders);
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
```html
|
|
361
|
+
<igx-grid #masterGrid
|
|
362
|
+
[data]="customers()"
|
|
363
|
+
[primaryKey]="'id'"
|
|
364
|
+
[rowSelection]="'single'"
|
|
365
|
+
(rowSelectionChanging)="onRowSelectionChanging($event)"
|
|
366
|
+
height="300px">
|
|
367
|
+
<igx-column field="name" header="Customer"></igx-column>
|
|
368
|
+
</igx-grid>
|
|
369
|
+
|
|
370
|
+
<igx-grid
|
|
371
|
+
[data]="customerOrders()"
|
|
372
|
+
[primaryKey]="'orderId'"
|
|
373
|
+
height="300px">
|
|
374
|
+
<igx-column field="orderId" header="Order"></igx-column>
|
|
375
|
+
<igx-column field="amount" header="Amount" dataType="number"></igx-column>
|
|
376
|
+
</igx-grid>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Key Rules
|
|
380
|
+
|
|
381
|
+
1. **Remote data requires `[totalItemCount]`** — without it, the virtual scrollbar won't size correctly
|
|
382
|
+
2. **Remote data requires noop strategies** — apply `NoopSortingStrategy` and `NoopFilteringStrategy` to disable client-side operations when the server handles them
|
|
383
|
+
3. **Track sort/filter state for remote operations** — store current expressions and include them in every server request
|
|
384
|
+
4. **Debounce rapid virtual scroll** — use `debounceTime` on `(dataPreLoad)` to avoid flooding the server
|
|
385
|
+
5. **Virtualization is automatic** — don't wrap grids in virtual scroll containers; just set a fixed `height`
|
|
386
|
+
6. **Use the correct component type for `viewChild`** — `IgxGridComponent`, `IgxTreeGridComponent`, `IgxHierarchicalGridComponent`, or `IgxPivotGridComponent`
|
|
387
|
+
7. **Import the correct directives/components** — `IGX_GRID_DIRECTIVES`, `IGX_TREE_GRID_DIRECTIVES`, `IGX_HIERARCHICAL_GRID_DIRECTIVES`, or `IGX_PIVOT_GRID_DIRECTIVES`
|
|
388
|
+
8. **Use signals for data** — `[data]="myData()"` with `signal<T[]>([])`
|
|
389
|
+
|
|
390
|
+
## See Also
|
|
391
|
+
|
|
392
|
+
- [`data-operations.md`](./data-operations.md) — Sorting, filtering, grouping, and canonical grid import patterns
|
|
393
|
+
- [`editing.md`](./editing.md) — Cell editing, row editing, batch editing, validation, summaries
|
|
394
|
+
- [`state.md`](./state.md) — State persistence, Tree Grid / Hierarchical Grid / Pivot Grid / Grid Lite data operations
|
|
395
|
+
- [`structure.md`](./structure.md) — Grid structure, column configuration, templates, layout, selection
|
|
396
|
+
- [`../../igniteui-angular-components/SKILL.md`](../../igniteui-angular-components/SKILL.md) — Non-grid Ignite UI components
|
|
397
|
+
- [`../../igniteui-angular-theming/SKILL.md`](../../igniteui-angular-theming/SKILL.md) — Theming & Styling
|