• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-angular / 13331632524

14 Feb 2025 02:51PM CUT coverage: 22.015% (-69.6%) from 91.622%
13331632524

Pull #15372

github

web-flow
Merge d52d57714 into bcb78ae0a
Pull Request #15372: chore(*): test ci passing

1990 of 15592 branches covered (12.76%)

431 of 964 new or added lines in 18 files covered. (44.71%)

19956 existing lines in 307 files now uncovered.

6452 of 29307 relevant lines covered (22.02%)

249.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.41
/projects/igniteui-angular/src/lib/grids/state-base.directive.ts
1
import { Directive, Optional, Input, Host, ViewContainerRef, Inject, createComponent, EnvironmentInjector, Injector } from '@angular/core';
2
import { IExpressionTree, IFilteringExpressionsTree } from '../data-operations/filtering-expressions-tree';
3
import { IgxColumnComponent } from './columns/column.component';
4
import { IgxColumnGroupComponent } from './columns/column-group.component';
5
import { IGroupingExpression } from '../data-operations/grouping-expression.interface';
6
import { IPagingState } from '../data-operations/paging-state.interface';
7
import { GridColumnDataType } from '../data-operations/data-util';
8
import { IGroupByExpandState } from '../data-operations/groupby-expand-state.interface';
9
import { IGroupingState } from '../data-operations/groupby-state.interface';
10
import { IgxGridComponent } from './grid/grid.component';
11
import { IgxHierarchicalGridComponent } from './hierarchical-grid/hierarchical-grid.component';
12
import { GridSelectionRange } from './common/types';
13
import { ISortingExpression } from '../data-operations/sorting-strategy';
14
import { ColumnType, FieldType, GridType, IGX_GRID_BASE, IPinningConfig } from './common/grid.interface';
15
import { IgxPivotGridComponent } from './pivot-grid/pivot-grid.component';
16
import { IPivotConfiguration, IPivotDimension } from './pivot-grid/pivot-grid.interface'
17
import { PivotUtil } from './pivot-grid/pivot-util';
18
import { IgxPivotDateDimension } from './pivot-grid/pivot-grid-dimensions';
19
import { cloneArray, cloneValue } from '../core/utils';
20
import { IgxColumnLayoutComponent } from './columns/column-layout.component';
21
import { recreateTreeFromFields } from '../data-operations/expressions-tree-util';
22

23
export interface IGridState {
24
    columns?: IColumnState[];
25
    filtering?: IFilteringExpressionsTree;
26
    advancedFiltering?: IFilteringExpressionsTree;
27
    paging?: IPagingState;
28
    moving?: boolean;
29
    sorting?: ISortingExpression[];
30
    groupBy?: IGroupingState;
31
    cellSelection?: GridSelectionRange[];
32
    /* blazorPrimitiveValue */
33
    rowSelection?: any[];
34
    columnSelection?: string[];
35
    /* blazorPrimitiveValue */
36
    rowPinning?: any[];
37
    pinningConfig?: IPinningConfig;
38
    /* blazorPrimitiveValue */
39
    expansion?: any[];
40
    rowIslands?: IGridStateCollection[];
41
    id?: string;
42
    pivotConfiguration?: IPivotConfiguration;
43
}
44

45
/* marshalByValue */
46
export interface IGridStateCollection {
47
    id: string;
48
    parentRowID: any;
49
    state: IGridState;
50
}
51

52
export interface IGridStateOptions {
53
    columns?: boolean;
54
    filtering?: boolean;
55
    advancedFiltering?: boolean;
56
    sorting?: boolean;
57
    groupBy?: boolean;
58
    paging?: boolean;
59
    cellSelection?: boolean;
60
    rowSelection?: boolean;
61
    columnSelection?: boolean;
62
    rowPinning?: boolean;
63
    pinningConfig?: boolean;
64
    expansion?: boolean;
65
    rowIslands?: boolean;
66
    moving?: boolean;
67
    pivotConfiguration?: boolean;
68
}
69

70
/* marshalByValue */
71
/* tsPlainInterface */
72
export interface IColumnState {
73
    pinned: boolean;
74
    sortable: boolean;
75
    filterable: boolean;
76
    editable: boolean;
77
    sortingIgnoreCase: boolean;
78
    filteringIgnoreCase: boolean;
79
    headerClasses: string;
80
    headerGroupClasses: string;
81
    maxWidth: string;
82
    groupable: boolean;
83
    hidden: boolean;
84
    dataType: GridColumnDataType;
85
    hasSummary: boolean;
86
    field: string;
87
    width: any;
88
    header: string;
89
    resizable: boolean;
90
    searchable: boolean;
91
    columnGroup: boolean;
92
    // mrl props
93
    columnLayout?: boolean;
94
    rowStart?: number,
95
    rowEnd?: number,
96
    colStart?: number;
97
    colEnd?: number,
98
    /**
99
     * @deprecated
100
     */
101
    parent?: any;
102
    key: string;
103
    parentKey: string;
104
    disableHiding: boolean;
105
    disablePinning: boolean;
106
    collapsible?: boolean;
107
    expanded?: boolean;
108
    visibleWhenCollapsed?: boolean;
109
}
110

111
export type GridFeatures = keyof IGridStateOptions;
112

113
interface Feature {
114
    getFeatureState: (context: IgxGridStateBaseDirective) => IGridState;
115
    restoreFeatureState: (context: IgxGridStateBaseDirective, state: IColumnState[] | IPagingState | boolean | ISortingExpression[] |
116
        IGroupingState | IFilteringExpressionsTree | GridSelectionRange[] | IPinningConfig | IPivotConfiguration | any[]) => void;
117
}
118

119
/* blazorElement */
120
/* wcElementTag: igc-grid-state-base-directive */
121
/* blazorIndirectRender */
122
@Directive()
123
export class IgxGridStateBaseDirective {
2✔
124

UNCOV
125
    private featureKeys: GridFeatures[] = [];
×
126
    private state: IGridState;
127
    private currGrid: GridType;
UNCOV
128
    protected _options: IGridStateOptions = {
×
129
        columns: true,
130
        filtering: true,
131
        advancedFiltering: true,
132
        sorting: true,
133
        groupBy: true,
134
        paging: true,
135
        cellSelection: true,
136
        rowSelection: true,
137
        columnSelection: true,
138
        rowPinning: true,
139
        expansion: true,
140
        moving: true,
141
        rowIslands: true,
142
        pivotConfiguration: true
143
    };
UNCOV
144
    private FEATURES = {
×
145
        sorting:  {
146
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
147
                const sortingState = context.currGrid.sortingExpressions;
×
UNCOV
148
                sortingState.forEach(s => {
×
UNCOV
149
                    delete s.strategy;
×
UNCOV
150
                    delete s.owner;
×
151
                });
UNCOV
152
                return { sorting: sortingState };
×
153
            },
154
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: ISortingExpression[]): void => {
UNCOV
155
                context.currGrid.sortingExpressions = state;
×
156
            }
157
        },
158
        filtering: {
159
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
160
                const filteringState = context.currGrid.filteringExpressionsTree;
×
UNCOV
161
                if (filteringState) {
×
UNCOV
162
                    delete filteringState.owner;
×
UNCOV
163
                    for (const item of filteringState.filteringOperands) {
×
UNCOV
164
                        delete (item as IFilteringExpressionsTree).owner;
×
165
                    }
166
                }
UNCOV
167
                return { filtering: filteringState };
×
168
            },
169
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: IFilteringExpressionsTree): void => {
UNCOV
170
                const filterTree = context.createExpressionsTreeFromObject(state);
×
NEW
171
                context.currGrid.filteringExpressionsTree = filterTree as IFilteringExpressionsTree;
×
172
            }
173
        },
174
        advancedFiltering: {
175
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
176
                const filteringState = context.currGrid.advancedFilteringExpressionsTree;
×
177
                let advancedFiltering: any;
UNCOV
178
                if (filteringState) {
×
UNCOV
179
                    delete filteringState.owner;
×
UNCOV
180
                    for (const item of filteringState.filteringOperands) {
×
UNCOV
181
                        delete (item as IFilteringExpressionsTree).owner;
×
182
                    }
UNCOV
183
                    advancedFiltering = filteringState;
×
184
                } else {
UNCOV
185
                    advancedFiltering = {};
×
186
                }
UNCOV
187
                return { advancedFiltering };
×
188
            },
189
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: IFilteringExpressionsTree): void => {
UNCOV
190
                const filterTree = context.createExpressionsTreeFromObject(state);
×
NEW
191
                context.currGrid.advancedFilteringExpressionsTree = filterTree as IFilteringExpressionsTree;
×
192
            }
193
        },
194
        columns: {
195
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
196
                const gridColumns: IColumnState[] = context.currGrid.columns.map((c) => ({
×
197
                    pinned: c.pinned,
198
                    sortable: c.sortable,
199
                    filterable: c.filterable,
200
                    editable: c.editable,
201
                    sortingIgnoreCase: c.sortingIgnoreCase,
202
                    filteringIgnoreCase: c.filteringIgnoreCase,
203
                    headerClasses: c.headerClasses,
204
                    headerGroupClasses: c.headerGroupClasses,
205
                    maxWidth: c.maxWidth,
206
                    groupable: c.groupable,
207
                    hidden: c.hidden,
208
                    dataType: c.dataType,
209
                    hasSummary: c.hasSummary,
210
                    field: c.field,
211
                    width: c.width,
212
                    header: c.header,
213
                    resizable: c.resizable,
214
                    searchable: c.searchable,
215
                    selectable: c.selectable,
216
                    key: c.columnGroup ? this.getColumnGroupKey(c) : c.field,
×
217
                    parentKey: c.parent ? this.getColumnGroupKey(c.parent) : undefined,
×
218
                    columnGroup: c.columnGroup,
219
                    columnLayout: c.columnLayout || undefined,
×
220
                    rowStart: c.parent?.columnLayout ? c.rowStart : undefined,
×
221
                    rowEnd: c.parent?.columnLayout ? c.rowEnd : undefined,
×
222
                    colStart: c.parent?.columnLayout ? c.colStart : undefined,
×
223
                    colEnd: c.parent?.columnLayout ? c.colEnd : undefined,
×
224
                    disableHiding: c.disableHiding,
225
                    disablePinning: c.disablePinning,
226
                    collapsible: c.columnGroup ? c.collapsible : undefined,
×
227
                    expanded: c.columnGroup ? c.expanded : undefined,
×
228
                    visibleWhenCollapsed: c.parent?.columnGroup ? (c as IgxColumnComponent).visibleWhenCollapsed : undefined
×
229
                }));
UNCOV
230
                return { columns: gridColumns };
×
231
            },
232
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: IColumnState[]): void => {
UNCOV
233
                const newColumns = [];
×
UNCOV
234
                state.forEach((colState) => {
×
UNCOV
235
                    const hasColumnGroup = colState.columnGroup;
×
UNCOV
236
                    const hasColumnLayouts = colState.columnLayout;
×
UNCOV
237
                    delete colState.columnGroup;
×
UNCOV
238
                    delete colState.columnLayout;
×
UNCOV
239
                    if (hasColumnGroup) {
×
UNCOV
240
                        let ref1: IgxColumnGroupComponent = context.currGrid.columns.find(x => x.columnGroup && (colState.key ? this.getColumnGroupKey(x) === colState.key : x.header === colState.header)) as IgxColumnGroupComponent;
×
UNCOV
241
                        if (!ref1) {
×
UNCOV
242
                            const component = hasColumnLayouts ?
×
243
                            createComponent(IgxColumnLayoutComponent, { environmentInjector: this.envInjector, elementInjector: this.injector }) :
244
                            createComponent(IgxColumnGroupComponent, { environmentInjector: this.envInjector, elementInjector: this.injector });
UNCOV
245
                            ref1 = component.instance;
×
UNCOV
246
                            component.changeDetectorRef.detectChanges();
×
247
                        } else {
UNCOV
248
                            ref1.children.reset([]);
×
249
                        }
UNCOV
250
                        Object.assign(ref1, colState);
×
UNCOV
251
                        ref1.grid = context.currGrid;
×
UNCOV
252
                        if (colState.parent || colState.parentKey) {
×
253
                            const columnGroup: IgxColumnGroupComponent = newColumns.find(e => e.columnGroup && (e.key ? e.key === colState.parentKey : e.header === ref1.parent));
×
254
                            columnGroup.children.reset([...columnGroup.children.toArray(), ref1]);
×
255
                            ref1.parent = columnGroup;
×
256
                        }
UNCOV
257
                        ref1.cdr.detectChanges();
×
UNCOV
258
                        newColumns.push(ref1);
×
259
                    } else {
UNCOV
260
                        let ref: IgxColumnComponent = context.currGrid.columns.find(x => !x.columnGroup && x.field === colState.field) as IgxColumnComponent;
×
UNCOV
261
                        if (!ref) {
×
UNCOV
262
                            const component = createComponent(IgxColumnComponent, { environmentInjector: this.envInjector, elementInjector: this.injector});
×
UNCOV
263
                            ref = component.instance;
×
UNCOV
264
                            component.changeDetectorRef.detectChanges();
×
265
                        }
266

UNCOV
267
                        Object.assign(ref, colState);
×
UNCOV
268
                        ref.grid = context.currGrid;
×
UNCOV
269
                        if (colState.parent || colState.parentKey) {
×
UNCOV
270
                            const columnGroup: IgxColumnGroupComponent = newColumns.find(e =>  e.columnGroup && (e.key ? e.key === colState.parentKey : e.header === ref.parent));
×
UNCOV
271
                            if (columnGroup) {
×
UNCOV
272
                                ref.parent = columnGroup;
×
UNCOV
273
                                columnGroup.children.reset([...columnGroup.children.toArray(), ref]);
×
274
                            }
275
                        }
UNCOV
276
                        ref.cdr.detectChanges();
×
UNCOV
277
                        newColumns.push(ref);
×
278
                    }
279
                });
UNCOV
280
                context.currGrid.updateColumns(newColumns);
×
UNCOV
281
                newColumns.forEach(col => {
×
UNCOV
282
                    (context.currGrid as any).columnInit.emit(col);
×
283
                });
284
            }
285
        },
286
        groupBy: {
287
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
288
                const grid = context.currGrid as IgxGridComponent;
×
UNCOV
289
                const groupingExpressions = grid.groupingExpressions;
×
UNCOV
290
                groupingExpressions.forEach(expr => {
×
UNCOV
291
                    delete expr.strategy;
×
292
                });
UNCOV
293
                const expansionState = grid.groupingExpansionState;
×
UNCOV
294
                const groupsExpanded = grid.groupsExpanded;
×
295

UNCOV
296
                return { groupBy: { expressions: groupingExpressions, expansion: expansionState, defaultExpanded: groupsExpanded}  };
×
297
            },
298
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: IGroupingState): void => {
UNCOV
299
                const grid = context.currGrid as IgxGridComponent;
×
UNCOV
300
                grid.groupingExpressions = state.expressions as IGroupingExpression[];
×
UNCOV
301
                state.expansion.forEach(exp => {
×
UNCOV
302
                    exp.hierarchy.forEach(h => {
×
UNCOV
303
                        const dataType = grid.columns.find(c => c.field === h.fieldName).dataType;
×
UNCOV
304
                        if (dataType.includes(GridColumnDataType.Date) || dataType.includes(GridColumnDataType.Time)) {
×
UNCOV
305
                            h.value = h.value ? new Date(Date.parse(h.value)) : h.value;
×
306
                        }
307
                    });
308
                });
UNCOV
309
                if (grid.groupsExpanded !== state.defaultExpanded) {
×
UNCOV
310
                    grid.toggleAllGroupRows();
×
311
                }
UNCOV
312
                grid.groupingExpansionState = state.expansion as IGroupByExpandState[];
×
313
            }
314
        },
315
        paging: {
316
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
317
                const pagingState = context.currGrid.pagingState;
×
UNCOV
318
                return { paging: pagingState };
×
319
            },
320
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: IPagingState): void => {
UNCOV
321
                if (!context.currGrid.paginator) {
×
322
                    return;
×
323
                }
UNCOV
324
                if (context.currGrid.perPage !== state.recordsPerPage) {
×
UNCOV
325
                    context.currGrid.perPage = state.recordsPerPage;
×
UNCOV
326
                    context.currGrid.cdr.detectChanges();
×
327
                }
UNCOV
328
                context.currGrid.page = state.index;
×
329
            }
330
        },
331
        moving: {
332
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
333
                return { moving: context.currGrid.moving };
×
334
            },
335
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: boolean): void => {
UNCOV
336
                context.currGrid.moving = state;
×
337
            }
338
        },
339
        rowSelection: {
340
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
341
                const selection = context.currGrid.selectionService.getSelectedRows();
×
UNCOV
342
                return { rowSelection: selection };
×
343
            },
344
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: any[]): void => {
UNCOV
345
                context.currGrid.selectRows(state, true);
×
346
            }
347
        },
348
        cellSelection: {
349
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
350
                const selection = context.currGrid.getSelectedRanges().map(range =>
×
UNCOV
351
                    ({ rowStart: range.rowStart, rowEnd: range.rowEnd, columnStart: range.columnStart, columnEnd: range.columnEnd }));
×
UNCOV
352
                return { cellSelection: selection };
×
353
            },
354
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: GridSelectionRange[]): void => {
UNCOV
355
                state.forEach(r => {
×
UNCOV
356
                    const range = { rowStart: r.rowStart, rowEnd: r.rowEnd, columnStart: r.columnStart, columnEnd: r.columnEnd};
×
UNCOV
357
                    context.currGrid.selectRange(range);
×
358
                });
359
            }
360
        },
361
        columnSelection: {
362
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
363
                const selection = context.currGrid.selectedColumns().map(c => c.field);
×
UNCOV
364
                return { columnSelection: selection };
×
365
            },
366
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: string[]): void => {
UNCOV
367
                context.currGrid.deselectAllColumns();
×
UNCOV
368
                context.currGrid.selectColumns(state);
×
369
            }
370
        },
371
        rowPinning: {
372
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
373
                const pinned = context.currGrid.pinnedRows?.map(x => x.key);
×
UNCOV
374
                return { rowPinning: pinned };
×
375
            },
376
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: any[]): void => {
377
                // clear current state.
UNCOV
378
                context.currGrid.pinnedRows.forEach(row => row.unpin());
×
UNCOV
379
                state.forEach(rowID => context.currGrid.pinRow(rowID));
×
380
            }
381
        },
382
        pinningConfig: {
383
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => ({ pinningConfig: context.currGrid.pinning }),
×
384
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: IPinningConfig): void => {
385
                context.currGrid.pinning = state;
×
386
            }
387
        },
388
        expansion: {
389
            getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
UNCOV
390
                const expansionStates = Array.from(context.currGrid.expansionStates);
×
UNCOV
391
                return { expansion: expansionStates };
×
392
            },
393
            restoreFeatureState: (context: IgxGridStateBaseDirective, state: any[]): void => {
UNCOV
394
                const expansionStates = new Map<any, boolean>(state);
×
UNCOV
395
                context.currGrid.expansionStates = expansionStates;
×
396
            }
397
        },
398
        rowIslands: {
399
            getFeatureState(context: IgxGridStateBaseDirective): IGridState {
UNCOV
400
                const childGridStates: IGridStateCollection[] = [];
×
UNCOV
401
                const rowIslands = (context.currGrid as any).allLayoutList;
×
UNCOV
402
                if (rowIslands) {
×
UNCOV
403
                    rowIslands.forEach(rowIsland => {
×
UNCOV
404
                        const childGrids = rowIsland.rowIslandAPI.getChildGrids();
×
UNCOV
405
                        childGrids.forEach(chGrid => {
×
UNCOV
406
                            const parentRowID = this.getParentRowID(chGrid);
×
UNCOV
407
                            context.currGrid = chGrid;
×
UNCOV
408
                            if (context.currGrid) {
×
UNCOV
409
                                const childGridState = context.buildState(context.featureKeys) as IGridState;
×
UNCOV
410
                                childGridStates.push({ id: `${rowIsland.id}`, parentRowID, state: childGridState });
×
411
                            }
412
                        });
413
                    });
414
                }
UNCOV
415
                context.currGrid = context.grid;
×
UNCOV
416
                return { rowIslands: childGridStates };
×
417
            },
418
            restoreFeatureState(context: IgxGridStateBaseDirective, state: any): void {
UNCOV
419
                const rowIslands = (context.currGrid as any).allLayoutList;
×
UNCOV
420
                if (rowIslands) {
×
UNCOV
421
                    rowIslands.forEach(rowIsland => {
×
UNCOV
422
                        const childGrids = rowIsland.rowIslandAPI.getChildGrids();
×
UNCOV
423
                        childGrids.forEach(chGrid => {
×
UNCOV
424
                            const parentRowID = this.getParentRowID(chGrid);
×
UNCOV
425
                            context.currGrid = chGrid;
×
UNCOV
426
                            const childGridState = state.find(st => st.id === rowIsland.id && st.parentRowID === parentRowID);
×
UNCOV
427
                            if (childGridState && context.currGrid) {
×
UNCOV
428
                                context.restoreGridState(childGridState.state, context.featureKeys);
×
429
                            }
430
                        });
431
                    });
432
                }
UNCOV
433
                context.currGrid = context.grid;
×
434
            },
435
            /**
436
             * Traverses the hierarchy up to the root grid to return the ID of the expanded row.
437
             */
438
            getParentRowID: (grid: IgxHierarchicalGridComponent) => {
439
                let childGrid;
UNCOV
440
                while (grid.parent) {
×
UNCOV
441
                    childGrid = grid;
×
UNCOV
442
                    grid = grid.parent;
×
443
                }
UNCOV
444
                return grid.gridAPI.getParentRowId(childGrid);
×
445
            }
446
        },
447
        pivotConfiguration: {
448
            getFeatureState(context: IgxGridStateBaseDirective): IGridState {
UNCOV
449
                const config = (context.currGrid as IgxPivotGridComponent).pivotConfiguration;
×
UNCOV
450
                if (!config || !(context.currGrid instanceof IgxPivotGridComponent)) {
×
UNCOV
451
                    return { pivotConfiguration: undefined };
×
452
                }
UNCOV
453
                const configCopy = cloneValue(config);
×
UNCOV
454
                configCopy.rows = cloneArray(config.rows, true);
×
UNCOV
455
                configCopy.columns = cloneArray(config.columns, true);
×
UNCOV
456
                configCopy.filters = cloneArray(config.filters, true);
×
UNCOV
457
                const dims =  [...(configCopy.rows || []), ...(configCopy.columns || []), ...(configCopy.filters || [])];
×
UNCOV
458
                const dateDimensions = dims.filter(x => context.isDateDimension(x));
×
UNCOV
459
                dateDimensions?.forEach(dim => {
×
460
                    // do not serialize the grid resource strings. This would pollute the object with unnecessary data.
UNCOV
461
                    (dim as IgxPivotDateDimension).resourceStrings = {};
×
462
                });
UNCOV
463
                return { pivotConfiguration: configCopy };
×
464
            },
465
            restoreFeatureState(context: IgxGridStateBaseDirective, state: any): void {
UNCOV
466
                const config: IPivotConfiguration = state;
×
UNCOV
467
                if (!config || !(context.currGrid instanceof IgxPivotGridComponent)) {
×
468
                    return;
×
469
                }
UNCOV
470
                context.restoreValues(config, context.currGrid as IgxPivotGridComponent);
×
UNCOV
471
                context.restoreDimensions(config);
×
UNCOV
472
                (context.currGrid as IgxPivotGridComponent).pivotConfiguration = config;
×
473
            },
474

475

476
        }
477
    };
478

479
    /**
480
     *  An object with options determining if a certain feature state should be saved.
481
     * ```html
482
     * <igx-grid [igxGridState]="options"></igx-grid>
483
     * ```
484
     * ```typescript
485
     * public options = {selection: false, advancedFiltering: false};
486
     * ```
487
     */
488
    @Input()
489
    public get options(): IGridStateOptions {
UNCOV
490
       return this._options;
×
491
    }
492

493
    public set options(value: IGridStateOptions) {
UNCOV
494
        Object.assign(this._options, value);
×
UNCOV
495
        if (!(this.grid instanceof IgxGridComponent)) {
×
UNCOV
496
            delete this._options.groupBy;
×
497
        } else {
UNCOV
498
            delete this._options.rowIslands;
×
499
        }
500
    }
501

502
    /**
503
     * @hidden
504
     */
505
    constructor(
UNCOV
506
        @Host() @Optional() @Inject(IGX_GRID_BASE) public grid: GridType,
×
UNCOV
507
        protected viewRef: ViewContainerRef, protected envInjector: EnvironmentInjector,  protected injector: Injector) { }
×
508

509
    /**
510
     * Gets the state of a feature or states of all grid features, unless a certain feature is disabled through the `options` property.
511
     *
512
     * @param `serialize` determines whether the returned object will be serialized to JSON string. Default value is true.
513
     * @param `feature` string or array of strings determining the features to be added in the state. If skipped, all features are added.
514
     * @returns Returns the serialized to JSON string IGridState object, or the non-serialized IGridState object.
515
     * ```html
516
     * <igx-grid [igxGridState]="options"></igx-grid>
517
     * ```
518
     * ```typescript
519
     * @ViewChild(IgxGridStateDirective, { static: true }) public state;
520
     * let state = this.state.getState(); // returns string
521
     * let state = this.state(false) // returns `IGridState` object
522
     * ```
523
     */
524
    protected getStateInternal(serialize = true, features?: GridFeatures | GridFeatures[]): IGridState | string  {
×
525
        let state: IGridState | string;
UNCOV
526
        this.currGrid = this.grid;
×
UNCOV
527
        this.state = state = this.buildState(features) as IGridState;
×
UNCOV
528
        if (serialize) {
×
UNCOV
529
            state = JSON.stringify(state, this.stringifyCallback) as string;
×
530
        }
UNCOV
531
        return state;
×
532
    }
533

534
    /* blazorSuppress */
535
    /**
536
     * Restores grid features' state based on the IGridState object passed as an argument.
537
     *
538
     * @param IGridState object to restore state from.
539
     * @returns
540
     * ```html
541
     * <igx-grid [igxGridState]="options"></igx-grid>
542
     * ```
543
     * ```typescript
544
     * @ViewChild(IgxGridStateDirective, { static: true }) public state;
545
     * this.state.setState(gridState);
546
     * ```
547
     */
548
    protected setStateInternal(state: IGridState, features?: GridFeatures | GridFeatures[]) {
UNCOV
549
        this.state = state;
×
UNCOV
550
        this.currGrid = this.grid;
×
UNCOV
551
        this.restoreGridState(state, features);
×
UNCOV
552
        this.grid.cdr.detectChanges(); // TODO
×
553
    }
554

555
    /**
556
     * Builds an IGridState object.
557
     */
558
    private buildState(keys?: GridFeatures | GridFeatures[]): IGridState {
UNCOV
559
        this.applyFeatures(keys);
×
UNCOV
560
        let gridState = {} as IGridState;
×
UNCOV
561
        this.featureKeys.forEach(f => {
×
UNCOV
562
            if (this.options[f]) {
×
UNCOV
563
                if (!(this.grid instanceof IgxGridComponent) && f === 'groupBy') {
×
564
                    return;
×
565
                }
UNCOV
566
                const feature = this.getFeature(f);
×
UNCOV
567
                const featureState: IGridState = feature?.getFeatureState(this);
×
UNCOV
568
                gridState = Object.assign(gridState, featureState);
×
569
            }
570
        });
UNCOV
571
        return gridState;
×
572
    }
573

574
    /**
575
     * The method that calls corresponding methods to restore features from the passed IGridState object.
576
     */
577
    private restoreGridState(state: IGridState, features?: GridFeatures | GridFeatures[]) {
UNCOV
578
        this.applyFeatures(features);
×
UNCOV
579
        this.restoreFeatures(state);
×
580
    }
581

582
    private restoreFeatures(state: IGridState) {
UNCOV
583
        this.featureKeys.forEach(f => {
×
UNCOV
584
            if (this.options[f]) {
×
UNCOV
585
                const featureState = state[f];
×
UNCOV
586
                if (f === 'moving' || featureState) {
×
UNCOV
587
                    const feature = this.getFeature(f);
×
UNCOV
588
                    feature.restoreFeatureState(this, featureState);
×
589
                }
590
            }
591
        });
592
    }
593

594
    /**
595
     * Returns a collection of all grid features.
596
     */
597
    private applyFeatures(keys?: GridFeatures | GridFeatures[]) {
UNCOV
598
        this.featureKeys = [];
×
UNCOV
599
        if (!keys) {
×
UNCOV
600
            for (const key of Object.keys(this.options)) {
×
UNCOV
601
                this.featureKeys.push(key as GridFeatures);
×
602
            }
UNCOV
603
        } else if (Array.isArray(keys)) {
×
UNCOV
604
            this.featureKeys = [...keys as GridFeatures[]];
×
605
        } else {
UNCOV
606
            this.featureKeys.push(keys);
×
607
        }
608
    }
609

610
    /**
611
     * This method restores complex objects in the pivot dimensions
612
     * Like the IgxPivotDateDimension and filters.
613
     */
614
    private restoreDimensions(config: IPivotConfiguration) {
UNCOV
615
        const collections = [config.rows, config.columns, config.filters];
×
UNCOV
616
        for (const collection of collections) {
×
UNCOV
617
            for (let index = 0; index < collection?.length; index++) {
×
UNCOV
618
                const dim = collection[index];
×
UNCOV
619
                if (this.isDateDimension(dim)) {
×
UNCOV
620
                   this.restoreDateDimension(dim as IgxPivotDateDimension);
×
621
                }
622
                // restore complex filters
UNCOV
623
                if (dim.filter) {
×
NEW
624
                    dim.filter = this.createExpressionsTreeFromObject(dim.filter) as IFilteringExpressionsTree;
×
625
                }
626
            }
627
        }
628
    }
629

630

631
    /**
632
     * This method restores the IgxPivotDateDimension with its default functions and resource strings.
633
     */
634
    private restoreDateDimension(dim: IgxPivotDateDimension) {
UNCOV
635
        const dateDim = new IgxPivotDateDimension((dim as any)._baseDimension, (dim as any)._options);
×
636
        // restore functions and resource strings
UNCOV
637
        dim.resourceStrings = dateDim.resourceStrings;
×
UNCOV
638
        dim.memberFunction = dateDim.memberFunction;
×
UNCOV
639
        let currDim: IPivotDimension = dim;
×
UNCOV
640
        let originDim: IPivotDimension = dateDim;
×
UNCOV
641
        while (currDim.childLevel) {
×
UNCOV
642
            currDim = currDim.childLevel;
×
UNCOV
643
            originDim = originDim.childLevel;
×
UNCOV
644
            currDim.memberFunction = originDim.memberFunction;
×
645
        }
646
    }
647

648
    /**
649
     * Returns if this is a IgxPivotDateDimension.
650
     */
651
    private isDateDimension(dim: IPivotDimension) {
UNCOV
652
        return (dim as any)._baseDimension;
×
653
    }
654

655
    /**
656
     * This method restores complex objects in the pivot values.
657
     * Like the default aggregator methods.
658
     */
659
    private restoreValues(config: IPivotConfiguration, grid: IgxPivotGridComponent) {
660
        // restore aggregator func if it matches the default aggregators key and label
UNCOV
661
        const values = config.values;
×
UNCOV
662
        for (const value of values) {
×
UNCOV
663
            const aggregateList = value.aggregateList;
×
UNCOV
664
            const aggregators = PivotUtil.getAggregatorsForValue(value, grid);
×
UNCOV
665
            value.aggregate.aggregator = aggregators.find(x => x.key === value.aggregate.key && x.label === value.aggregate.label)?.aggregator;
×
UNCOV
666
            if (aggregateList) {
×
667
                for (const ag of aggregateList) {
×
668
                    ag.aggregator = aggregators.find(x => x.key === ag.key && x.label === ag.label)?.aggregator;
×
669
                }
670
            }
671
        }
672
    }
673

674
    /**
675
     * This method builds a rehydrated IExpressionTree from a provided object.
676
     */
677
    private createExpressionsTreeFromObject(exprTreeObject: IExpressionTree): IExpressionTree {
UNCOV
678
        if (!exprTreeObject || !exprTreeObject.filteringOperands) {
×
UNCOV
679
            return null;
×
680
        }
681

NEW
682
        if (this.currGrid instanceof IgxPivotGridComponent) {
×
NEW
683
            return recreateTreeFromFields(exprTreeObject, this.currGrid.allDimensions.map(d => ({ dataType: d.dataType, field: d.memberName })) as FieldType[]) as IExpressionTree;
×
684
        }
685

NEW
686
        return recreateTreeFromFields(exprTreeObject, this.currGrid.columns) as IExpressionTree;
×
687
    }
688

689
    protected stringifyCallback(key: string, val: any) {
UNCOV
690
        if (key === 'searchVal' && val instanceof Set) {
×
691
            return Array.from(val);
×
692
        }
UNCOV
693
        return val;
×
694
    }
695

696
    private getColumnGroupKey(columnGroup: ColumnType) : string {
UNCOV
697
        return columnGroup.childColumns.map(x => x.columnGroup ? x.level + "_" + this.getColumnGroupKey(x) : x.field).sort().join("_");
×
698
    }
699

700
    private getFeature(key: string): Feature {
UNCOV
701
        const feature: Feature = this.FEATURES[key];
×
UNCOV
702
        return feature;
×
703
    }
704
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc