Skip to content

Commit d9cbd2a

Browse files
Copilotivanvpetrov
andcommitted
fix(grid-state): avoid mutating sortingExpressions and filteringExpressionsTree in getState
Co-authored-by: ivanvpetrov <110455887+ivanvpetrov@users.noreply.github.com> Agent-Logs-Url: https://github.com/IgniteUI/igniteui-angular/sessions/a49800a1-77b4-49ff-8685-0fc3b9034200
1 parent f9caf7b commit d9cbd2a

3 files changed

Lines changed: 62 additions & 77 deletions

File tree

package-lock.json

Lines changed: 0 additions & 64 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

projects/igniteui-angular/grids/core/src/state-base.directive.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,11 @@ export class IgxGridStateBaseDirective {
139139
private FEATURES = {
140140
sorting: {
141141
getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
142-
const sortingState = context.currGrid.sortingExpressions;
143-
sortingState.forEach(s => {
144-
delete s.strategy;
145-
delete s.owner;
142+
const sortingState = context.currGrid.sortingExpressions.map(s => {
143+
const copy: any = { ...s };
144+
delete copy.strategy;
145+
delete copy.owner;
146+
return copy;
146147
});
147148
return { sorting: sortingState };
148149
},
@@ -154,10 +155,14 @@ export class IgxGridStateBaseDirective {
154155
getFeatureState: (context: IgxGridStateBaseDirective): IGridState => {
155156
const filteringState = context.currGrid.filteringExpressionsTree;
156157
if (filteringState) {
157-
delete filteringState.owner;
158-
for (const item of filteringState.filteringOperands) {
159-
delete (item as IFilteringExpressionsTree).owner;
160-
}
158+
const filterCopy: any = { ...filteringState };
159+
delete filterCopy.owner;
160+
filterCopy.filteringOperands = filteringState.filteringOperands.map(item => {
161+
const itemCopy: any = { ...item };
162+
delete itemCopy.owner;
163+
return itemCopy;
164+
});
165+
return { filtering: filterCopy as IFilteringExpressionsTree };
161166
}
162167
return { filtering: filteringState };
163168
},
@@ -171,11 +176,14 @@ export class IgxGridStateBaseDirective {
171176
const filteringState = context.currGrid.advancedFilteringExpressionsTree;
172177
let advancedFiltering: any;
173178
if (filteringState) {
174-
delete filteringState.owner;
175-
for (const item of filteringState.filteringOperands) {
176-
delete (item as IFilteringExpressionsTree).owner;
177-
}
178-
advancedFiltering = filteringState;
179+
const filterCopy: any = { ...filteringState };
180+
delete filterCopy.owner;
181+
filterCopy.filteringOperands = filteringState.filteringOperands.map(item => {
182+
const itemCopy: any = { ...item };
183+
delete itemCopy.owner;
184+
return itemCopy;
185+
});
186+
advancedFiltering = filterCopy;
179187
} else {
180188
advancedFiltering = {};
181189
}

projects/igniteui-angular/grids/core/src/state.directive.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,47 @@ describe('IgxGridState - input properties #grid', () => {
803803
expect(prodIdColumn.colEnd).toBe(1);
804804
});
805805

806+
it('getState should not mutate sortingExpressions - strategy and owner should be preserved', () => {
807+
const fix = TestBed.createComponent(IgxGridStateComponent);
808+
fix.detectChanges();
809+
const grid = fix.componentInstance.grid;
810+
const state = fix.componentInstance.state;
811+
812+
const sortingStrategy = DefaultSortingStrategy.instance();
813+
grid.sortingExpressions = [
814+
{ fieldName: 'ProductID', dir: SortingDirection.Asc, ignoreCase: false, strategy: sortingStrategy }
815+
];
816+
fix.detectChanges();
817+
818+
state.getState(false, 'sorting');
819+
820+
expect(grid.sortingExpressions[0].strategy).toBe(sortingStrategy,
821+
'strategy should not be deleted from the original sortingExpression after calling getState');
822+
});
823+
824+
it('getState should not mutate filteringExpressionsTree - owner should be preserved', () => {
825+
const fix = TestBed.createComponent(IgxGridStateComponent);
826+
fix.detectChanges();
827+
const grid = fix.componentInstance.grid;
828+
const state = fix.componentInstance.state;
829+
830+
const gridFilteringExpressionsTree = new FilteringExpressionsTree(FilteringLogic.And);
831+
const productFilteringExpressionsTree = new FilteringExpressionsTree(FilteringLogic.And, 'InStock');
832+
const ownerRef = {};
833+
(gridFilteringExpressionsTree as any).owner = ownerRef;
834+
(productFilteringExpressionsTree as any).owner = ownerRef;
835+
gridFilteringExpressionsTree.filteringOperands.push(productFilteringExpressionsTree);
836+
grid.filteringExpressionsTree = gridFilteringExpressionsTree;
837+
fix.detectChanges();
838+
839+
state.getState(false, 'filtering');
840+
841+
expect((grid.filteringExpressionsTree as any).owner).toBe(ownerRef,
842+
'owner should not be deleted from the original filteringExpressionsTree after calling getState');
843+
expect((grid.filteringExpressionsTree.filteringOperands[0] as any).owner).toBe(ownerRef,
844+
'owner should not be deleted from the original filteringOperands after calling getState');
845+
});
846+
806847
it('should preserve column widths when restoring state with all columns hidden', () => {
807848
const fix = TestBed.createComponent(IgxGridStateComponent);
808849
fix.detectChanges();

0 commit comments

Comments
 (0)