diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-search.component.ts b/projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-search.component.ts index ba00843097b..aabaffecde2 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-search.component.ts +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-search.component.ts @@ -29,6 +29,7 @@ export class IgxExcelStyleLoadingValuesTemplateDirective { } let NEXT_ID = 0; +const TREE_GRID_GROUPING_HIDDEN_FIELD = '_Igx_Hidden_Data_'; /** * A component used for presenting Excel style search UI. */ @@ -611,7 +612,7 @@ export class IgxExcelStyleSearchComponent implements AfterViewInit, OnDestroy { searchVal = new Set(selectedItems.map(e => e.value.toLocaleTimeString())); break; case GridColumnDataType.String: - if (this.esf.column.filteringIgnoreCase && !this.isHierarchical()) { + if (this.esf.column.filteringIgnoreCase && !this.isHierarchical() && !this.isTreeGridWithGroupBy()) { const selectedValues = new Set(selectedItems.map(item => item.value.toLowerCase())); searchVal = new Set(); @@ -897,4 +898,12 @@ export class IgxExcelStyleSearchComponent implements AfterViewInit, OnDestroy { const subRequired = indexOutOfChunk || scrollNeeded; return subRequired; } + + private isTreeGridWithGroupBy(): boolean { + if (this.esf.grid.type !== 'tree') { + return false; + } + const data = this.esf.grid.data; + return Array.isArray(data) && data.some(item => item && typeof item === 'object' && TREE_GRID_GROUPING_HIDDEN_FIELD in item); + } } diff --git a/projects/igniteui-angular/grids/tree-grid/src/tree-grid-grouping.spec.ts b/projects/igniteui-angular/grids/tree-grid/src/tree-grid-grouping.spec.ts index f9e23d9725c..b23b7b34ae0 100644 --- a/projects/igniteui-angular/grids/tree-grid/src/tree-grid-grouping.spec.ts +++ b/projects/igniteui-angular/grids/tree-grid/src/tree-grid-grouping.spec.ts @@ -6,6 +6,7 @@ import { IgxTreeGridGroupByAreaComponent } from 'igniteui-angular/grids/tree-gri import { TreeGridFunctions } from '../../../test-utils/tree-grid-functions.spec'; import { IgxTreeGridComponent } from './tree-grid.component'; import { DefaultSortingStrategy } from 'igniteui-angular/core'; +import { GridFunctions } from 'igniteui-angular/test-utils/grid-functions.spec'; describe('IgxTreeGrid', () => { @@ -24,7 +25,7 @@ describe('IgxTreeGrid', () => { let groupByArea: IgxTreeGridGroupByAreaComponent; const DROP_AREA_MSG = 'Drag a column header and drop it here to group by that column.'; - describe(' GroupByArea Standalone', ()=> { + describe(' GroupByArea Standalone', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridGroupByAreaTestComponent); @@ -53,7 +54,7 @@ describe('IgxTreeGrid', () => { expect(spanElement.innerText).toEqual(DROP_AREA_MSG); })); - it ('has the expected default properties\' values', fakeAsync(() => { + it('has the expected default properties\' values', fakeAsync(() => { expect(groupByArea).toBeDefined(); expect(groupByArea.grid).toEqual(treeGrid); expect(groupByArea.expressions).toEqual([]); @@ -97,7 +98,7 @@ describe('IgxTreeGrid', () => { clearGridSubs(); }); - it ('GroupByArea has the expected properties\' values set', fakeAsync(() => { + it('GroupByArea has the expected properties\' values set', fakeAsync(() => { expect(groupByArea).toBeDefined(); expect(groupByArea.expressions.length).toEqual(2); expect(groupByArea.grid).toEqual(treeGrid); @@ -132,7 +133,7 @@ describe('IgxTreeGrid', () => { expect(chips[0].id).toEqual('OnPTO'); expect(chips[1].id).toEqual('HireDate'); - groupingExpressions.push({ fieldName: 'JobTitle', dir: 2, ignoreCase: true, strategy: DefaultSortingStrategy.instance()}); + groupingExpressions.push({ fieldName: 'JobTitle', dir: 2, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); fix.detectChanges(); tick(); @@ -180,7 +181,7 @@ describe('IgxTreeGrid', () => { expect(treeGrid.getColumnByName('HireDate').hidden).toBeFalse(); - groupingExpressions.push({ fieldName: 'JobTitle', dir: 2, ignoreCase: true, strategy: DefaultSortingStrategy.instance()}); + groupingExpressions.push({ fieldName: 'JobTitle', dir: 2, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); groupByArea.expressions = [...groupingExpressions]; fix.detectChanges(); tick(); @@ -195,7 +196,7 @@ describe('IgxTreeGrid', () => { const aggregations = [{ field: 'HireDate', aggregate: (_parent: any, children: any[]) => children.map((c) => c.HireDate) - .reduce((min, c) => min < c ? min : c, new Date()) + .reduce((min, c) => min < c ? min : c, new Date()) }]; fix.componentInstance.aggregations = aggregations; @@ -296,6 +297,51 @@ describe('IgxTreeGrid', () => { expect(treeGrid.getColumnByName('OnPTO').hidden).toBeTrue(); expect(treeGrid.getColumnByName('HireDate').hidden).toBeTrue(); })); + + it('should handle excel style filtering when grouping is applied and 3 or more items are selected', fakeAsync(() => { + treeGrid.filterMode = "excelStyleFilter"; + treeGrid.allowFiltering = true; + treeGrid.expansionDepth = Infinity; + fix.detectChanges(); + GridFunctions.clickExcelFilterIconFromCode(fix, treeGrid, 'Name'); + const checkboxes = GridFunctions.getExcelStyleFilteringCheckboxes(fix, null, 'igx-tree-grid'); + // unselect all + checkboxes[0].click(); + fix.detectChanges(); + + checkboxes[2].click(); + checkboxes[3].click(); + checkboxes[4].click(); + fix.detectChanges(); + + GridFunctions.clickApplyExcelStyleFiltering(fix, null, 'igx-tree-grid'); + fix.detectChanges(); + + + expect(treeGrid.filteredData.length).toEqual(8); + })); + + it('should handle excel style filtering when grouping is applied and preserve all checked esf items', fakeAsync(() => { + treeGrid.filterMode = "excelStyleFilter"; + treeGrid.allowFiltering = true; + treeGrid.expansionDepth = Infinity; + fix.detectChanges(); + GridFunctions.clickExcelFilterIconFromCode(fix, treeGrid, 'Name'); + let checkboxes: HTMLInputElement[] = Array.from(GridFunctions.getExcelStyleFilteringCheckboxes(fix, null, 'igx-tree-grid') as HTMLInputElement[]); + // unselect just one + checkboxes[2].click(); + fix.detectChanges(); + + GridFunctions.clickApplyExcelStyleFiltering(fix, null, 'igx-tree-grid'); + fix.detectChanges(); + + GridFunctions.clickExcelFilterIconFromCode(fix, treeGrid, 'Name'); + checkboxes = Array.from(GridFunctions.getExcelStyleFilteringCheckboxes(fix, null, 'igx-tree-grid') as HTMLInputElement[]); + + const uncheckedItem = checkboxes.splice(2, 1)[0]; + expect(uncheckedItem.checked).toBeFalse(); + checkboxes.forEach(c => expect(c.checked).toBeTrue()); + })); }); const getChips = (fixture) => { diff --git a/projects/igniteui-angular/test-utils/tree-grid-components.spec.ts b/projects/igniteui-angular/test-utils/tree-grid-components.spec.ts index adf53ef89db..2c233413eac 100644 --- a/projects/igniteui-angular/test-utils/tree-grid-components.spec.ts +++ b/projects/igniteui-angular/test-utils/tree-grid-components.spec.ts @@ -1074,19 +1074,19 @@ export class IgxTreeGridCascadingSelectionTransactionComponent { @Component({ template: ` + [childDataKey]="childDataKey" [expansionDepth]="0" width="900px" height="1000px" > - - - - - - - + + + + + + + `, changeDetection: ChangeDetectionStrategy.Eager,