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..feade52d8d2 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 @@ -502,7 +502,7 @@ export class IgxExcelStyleSearchComponent implements AfterViewInit, OnDestroy { (it.label !== null && it.label !== undefined) && !it.isBlanks && (it.label.toString().toLowerCase().indexOf(searchVal) > -1 || - this.matchesNumericValue(it, searchVal))); + this.matchesNumericValue(it, searchVal))); this.esf.listData.forEach(i => i.isSelected = false); this.displayedListData.forEach(i => i.isSelected = true); @@ -611,7 +611,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.isRemoteData()) { const selectedValues = new Set(selectedItems.map(item => item.value.toLowerCase())); searchVal = new Set(); @@ -817,8 +817,8 @@ export class IgxExcelStyleSearchComponent implements AfterViewInit, OnDestroy { const columnDataType = this.esf.column?.dataType; if (typeof item.value !== 'number' || (columnDataType !== GridColumnDataType.Number && - columnDataType !== GridColumnDataType.Currency && - columnDataType !== GridColumnDataType.Percent)) { + columnDataType !== GridColumnDataType.Currency && + columnDataType !== GridColumnDataType.Percent)) { return false; } @@ -897,4 +897,8 @@ export class IgxExcelStyleSearchComponent implements AfterViewInit, OnDestroy { const subRequired = indexOutOfChunk || scrollNeeded; return subRequired; } + + private isRemoteData(): boolean { + return this.esf.grid.verticalScrollContainer.isRemote; + } } diff --git a/projects/igniteui-angular/grids/grid/src/grid-filtering-ui.spec.ts b/projects/igniteui-angular/grids/grid/src/grid-filtering-ui.spec.ts index 8e4813a10ce..ead0ee46145 100644 --- a/projects/igniteui-angular/grids/grid/src/grid-filtering-ui.spec.ts +++ b/projects/igniteui-angular/grids/grid/src/grid-filtering-ui.spec.ts @@ -24,6 +24,7 @@ import { IgxGridFilteringESFEmptyTemplatesComponent, IgxGridFilteringESFTemplatesComponent, IgxGridFilteringESFLoadOnDemandComponent, + IgxGridFilteringESFRemoteChunkComponent, CustomFilteringStrategyComponent, IgxGridExternalESFComponent, IgxGridExternalESFTemplateComponent, @@ -3223,6 +3224,7 @@ describe('IgxGrid - Filtering actions - Excel style filtering #grid', () => { IgxGridFilteringESFEmptyTemplatesComponent, IgxGridFilteringESFTemplatesComponent, IgxGridFilteringESFLoadOnDemandComponent, + IgxGridFilteringESFRemoteChunkComponent, IgxGridFilteringMCHComponent, IgxGridExternalESFComponent, IgxGridExternalESFTemplateComponent @@ -7068,6 +7070,40 @@ describe('IgxGrid - Filtering actions - Excel style filtering #grid', () => { tick(2000); }).not.toThrowError(/'dataType' of null/); })); + + it('Should preserve selected string values from full remote set when grid data is chunked', fakeAsync(() => { + const remoteFix = TestBed.createComponent(IgxGridFilteringESFRemoteChunkComponent); + const remoteGrid = remoteFix.componentInstance.grid; + remoteFix.detectChanges(); + + // Mark the grid as remote so ESF does not derive selected values from the current data chunk. + remoteGrid.totalItemCount = remoteFix.componentInstance.fullData.length; + + GridFunctions.clickExcelFilterIcon(remoteFix, 'ProductName'); + tick(100); + remoteFix.detectChanges(); + + const excelMenu = GridFunctions.getExcelStyleFilteringComponent(remoteFix); + const labelElements: any[] = Array.from(GridFunctions.getExcelStyleSearchComponentListItems(remoteFix, excelMenu)); + const checkboxElements: any[] = Array.from(GridFunctions.getExcelStyleFilteringCheckboxes(remoteFix, excelMenu)); + + const uncheckLabel = 'Alpha'; + const uncheckIndex = labelElements.findIndex(el => el.innerText === uncheckLabel); + expect(uncheckIndex).toBeGreaterThan(0); + + checkboxElements[uncheckIndex].click(); + remoteFix.detectChanges(); + + GridFunctions.clickApplyExcelStyleFiltering(remoteFix, excelMenu, 'igx-grid'); + remoteFix.detectChanges(); + + const tree = remoteGrid.filteringExpressionsTree.filteringOperands[0] as IFilteringExpressionsTree; + const operand = tree.filteringOperands[0] as IFilteringExpression; + + const selectedValues = Array.from((operand.searchVal as Set).values()); + expect(selectedValues).toEqual(jasmine.arrayContaining(['beta', 'Gamma', 'DELTA'])); + expect(selectedValues).not.toContain('Alpha'); + })); }); describe(null, () => { diff --git a/projects/igniteui-angular/test-utils/grid-samples.spec.ts b/projects/igniteui-angular/test-utils/grid-samples.spec.ts index 78ef55e83a3..086bd78e35c 100644 --- a/projects/igniteui-angular/test-utils/grid-samples.spec.ts +++ b/projects/igniteui-angular/test-utils/grid-samples.spec.ts @@ -918,6 +918,37 @@ export class IgxGridFilteringESFLoadOnDemandComponent extends BasicGridComponent }; } +@Component({ + template: ` + + + `, + changeDetection: ChangeDetectionStrategy.Eager, + imports: [IgxGridComponent, IgxColumnComponent] +}) +export class IgxGridFilteringESFRemoteChunkComponent extends BasicGridComponent { + public fullData = [ + { ID: 1, ProductName: 'Alpha' }, + { ID: 2, ProductName: 'beta' }, + { ID: 3, ProductName: 'Gamma' }, + { ID: 4, ProductName: 'DELTA' } + ]; + + // Simulate remote virtualization where the grid keeps only the current chunk. + public override data = this.fullData.slice(0, 2); + + private _filteringStrategy = new FilteringStrategy(); + + public columnValuesStrategy = (column: IgxColumnComponent, + columnExprTree: IFilteringExpressionsTree, + done: (uniqueValues: any[]) => void) => { + const filteredData = this._filteringStrategy.filter(this.fullData, columnExprTree, null, null); + const columnValues = filteredData.map(record => record[column.field]); + done(columnValues); + }; +} + @Component({ template: `