Skip to content

Commit 7929737

Browse files
authored
Merge branch 'master' into rivanova/fix-16288-master
2 parents 81b3fee + 7d649d9 commit 7929737

File tree

10 files changed

+174
-102
lines changed

10 files changed

+174
-102
lines changed

projects/igniteui-angular/src/lib/data-operations/data-util.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { IPagingState, PagingError } from './paging-state.interface';
55
import { IGroupByKey } from './groupby-expand-state.interface';
66
import { IGroupByRecord } from './groupby-record.interface';
77
import { IGroupingState } from './groupby-state.interface';
8-
import { mergeObjects } from '../core/utils';
8+
import { cloneArray, mergeObjects } from '../core/utils';
99
import { Transaction, TransactionType, HierarchicalTransaction } from '../services/transaction/transaction';
1010
import { getHierarchy, isHierarchyMatch } from './operations';
1111
import { ColumnType, GridType } from '../grids/common/grid.interface';
@@ -21,6 +21,8 @@ import {
2121
import { DefaultDataCloneStrategy, IDataCloneStrategy } from '../data-operations/data-clone-strategy';
2222
import { IGroupingExpression } from './grouping-expression.interface';
2323
import { DefaultMergeStrategy, IGridMergeStrategy } from './merge-strategy';
24+
import { IFilteringExpressionsTree } from './filtering-expressions-tree';
25+
import { FilteringStrategy, FilterUtil } from './filtering-strategy';
2426

2527
/**
2628
* @hidden
@@ -278,6 +280,15 @@ export class DataUtil {
278280
return value;
279281
}
280282

283+
public static filterDataByExpressions(data: any[], expressionsTree: IFilteringExpressionsTree, grid: GridType): any {
284+
if (expressionsTree.filteringOperands.length) {
285+
const state = { expressionsTree, strategy: FilteringStrategy.instance() };
286+
data = FilterUtil.filter(cloneArray(data), state, grid);
287+
}
288+
289+
return data;
290+
}
291+
281292
private static findParentFromPath(data: any[], primaryKey: any, childDataKey: any, path: any[]): any {
282293
let collection: any[] = data;
283294
let result: any;

projects/igniteui-angular/src/lib/data-operations/filtering-strategy.ts

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import { FilteringLogic, type IFilteringExpression } from './filtering-expressio
22
import { FilteringExpressionsTree, type IFilteringExpressionsTree } from './filtering-expressions-tree';
33
import { resolveNestedPath, parseDate, formatDate, formatCurrency, columnFieldPath } from '../core/utils';
44
import type { ColumnType, EntityType, GridType } from '../grids/common/grid.interface';
5-
import { GridColumnDataType } from './data-util';
5+
import { DataUtil, GridColumnDataType } from './data-util';
66
import { SortingDirection } from './sorting-strategy';
77
import { formatNumber, formatPercent, getLocaleCurrencyCode } from '@angular/common';
88
import type { IFilteringState } from './filtering-state.interface';
99
import { isTree } from './expressions-tree-util';
1010
import type { IgxHierarchicalGridComponent } from '../grids/hierarchical-grid/hierarchical-grid.component';
11+
import { IgxSorting } from '../grids/common/strategy';
1112

1213
const DateType = 'date';
1314
const DateTimeType = 'dateTime';
@@ -132,27 +133,35 @@ export abstract class BaseFilteringStrategy implements IFilteringStrategy {
132133
public getFilterItems(column: ColumnType, tree: IFilteringExpressionsTree): Promise<IgxFilterItem[]> {
133134
const applyFormatter = column.formatter && this.shouldFormatFilterValues(column);
134135

135-
let data = column.grid.gridAPI.filterDataByExpressions(tree);
136-
data = column.grid.gridAPI.sortDataByExpressions(data,
137-
[{ fieldName: column.field, dir: SortingDirection.Asc, ignoreCase: column.sortingIgnoreCase }]);
138-
136+
const data = this.getFilteredData(column, tree);
139137

140138
const pathParts = columnFieldPath(column.field)
141-
let filterItems: IgxFilterItem[] = data.map(record => {
142-
const value = applyFormatter ?
143-
column.formatter(resolveNestedPath(record, pathParts), record) :
144-
resolveNestedPath(record, pathParts);
145-
146-
return {
147-
value,
148-
label: this.getFilterItemLabel(column, value, !applyFormatter, record)
149-
};
150-
});
151-
filterItems = this.getUniqueFilterItems(column, filterItems);
139+
const seenFormattedFilterItems = new Map<any, IgxFilterItem>()
140+
141+
for (let i = 0; i < data.length; ++i) {
142+
const record = data[i]
143+
const rawValue = resolveNestedPath(record, pathParts);
144+
const formattedValue = applyFormatter ? column.formatter(rawValue, record) : rawValue;
145+
const { key, finalValue } = this.getFilterItemKeyValue(formattedValue, column);
146+
// Deduplicate by normalized key
147+
if (!seenFormattedFilterItems.has(key)) {
148+
const label = this.getFilterItemLabel(column, finalValue, !applyFormatter, record);
149+
seenFormattedFilterItems.set(key, { value: finalValue, label });
150+
}
151+
}
152+
153+
let filterItems: IgxFilterItem[] = Array.from(seenFormattedFilterItems.values());
154+
155+
filterItems = DataUtil.sort(filterItems,
156+
[{ fieldName: 'value', dir: SortingDirection.Asc, ignoreCase: column.sortingIgnoreCase }], new IgxSorting())
152157

153158
return Promise.resolve(filterItems);
154159
}
155160

161+
protected getFilteredData(column: ColumnType, tree: IFilteringExpressionsTree) {
162+
return column.grid.gridAPI.filterDataByExpressions(tree);
163+
}
164+
156165
protected getFilterItemLabel(column: ColumnType, value: any, applyFormatter: boolean, data: any) {
157166
if (column.formatter) {
158167
if (applyFormatter) {
@@ -180,30 +189,33 @@ export abstract class BaseFilteringStrategy implements IFilteringStrategy {
180189
}
181190
}
182191

183-
protected getUniqueFilterItems(column: ColumnType, filterItems: IgxFilterItem[]) {
184-
const filteredUniqueValues = filterItems.reduce((map, item) => {
185-
let key = item.value;
186-
187-
if (column.dataType === GridColumnDataType.String && column.filteringIgnoreCase) {
188-
key = key?.toString().toLowerCase();
189-
} else if (column.dataType === GridColumnDataType.DateTime) {
190-
key = item.value?.toString();
191-
item.value = key ? new Date(key) : key;
192-
} else if (column.dataType === GridColumnDataType.Time) {
193-
const date = key ? new Date(key) : key;
194-
key = date ? new Date().setHours(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()) : key;
195-
item.value = key ? new Date(key) : key;
196-
} else if (column.dataType === GridColumnDataType.Date) {
197-
const date = key ? new Date(key) : key;
198-
key = date ? new Date(date.getFullYear(), date.getMonth(), date.getDate()).toISOString() : key;
199-
item.value = date;
200-
}
201-
202-
return map.has(key) ? map : map.set(key, item)
203-
}, new Map());
204-
const uniqueValues = Array.from(filteredUniqueValues.values());
205-
206-
return uniqueValues;
192+
protected getFilterItemKeyValue(value: any, column: ColumnType) {
193+
let key: any = value;
194+
let finalValue = value;
195+
if (column.dataType === GridColumnDataType.String && column.filteringIgnoreCase) {
196+
key = key?.toString().toLowerCase();
197+
} else if (column.dataType === GridColumnDataType.DateTime) {
198+
key = value?.toString();
199+
finalValue = key ? new Date(key) : key;
200+
} else if (column.dataType === GridColumnDataType.Time) {
201+
const date = key ? new Date(key) : key;
202+
key = date
203+
? new Date().setHours(
204+
date.getHours(),
205+
date.getMinutes(),
206+
date.getSeconds(),
207+
date.getMilliseconds()
208+
)
209+
: date;
210+
finalValue = key ? new Date(key) : key;
211+
} else if (column.dataType === GridColumnDataType.Date) {
212+
const date = key ? new Date(key) : key;
213+
key = date
214+
? new Date(date.getFullYear(), date.getMonth(), date.getDate()).toISOString()
215+
: date;
216+
finalValue = date;
217+
}
218+
return { key, finalValue };
207219
}
208220

209221
protected shouldFormatFilterValues(_column: ColumnType): boolean {

projects/igniteui-angular/src/lib/grids/filtering/excel-style/base-filtering.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export abstract class BaseFilteringComponent {
2323
public abstract columnChange: EventEmitter<any>;
2424
public abstract sortingChanged: EventEmitter<undefined>;
2525
public abstract listDataLoaded: EventEmitter<undefined>;
26+
public abstract filterCleared: EventEmitter<undefined>;
2627

2728
constructor(
2829
protected cdr: ChangeDetectorRef,

projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-clear-filters.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class IgxExcelStyleClearFiltersComponent {
3434
*/
3535
public clearFilter() {
3636
this.esf.grid.filteringService.clearFilter(this.esf.column.field);
37+
this.esf.filterCleared.emit();
3738
this.selectAllFilterItems();
3839
}
3940

projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-filtering.component.ts

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ export class IgxGridExcelStyleFilteringComponent extends BaseFilteringComponent
128128
@Output()
129129
public listDataLoaded = new EventEmitter();
130130

131+
/**
132+
* @hidden @internal
133+
*/
134+
@Output()
135+
public filterCleared = new EventEmitter();
136+
131137
@ViewChild('mainDropdown', { read: ElementRef })
132138
public mainDropdown: ElementRef<HTMLElement>;
133139

@@ -160,29 +166,13 @@ export class IgxGridExcelStyleFilteringComponent extends BaseFilteringComponent
160166
*/
161167
@Input()
162168
public set column(value: ColumnType) {
163-
this._column = value;
164-
this.listData = new Array<FilterListItem>();
165-
this.columnChange.emit(this._column);
166-
167-
this.subscriptions?.unsubscribe();
168-
169-
if (this._column) {
170-
this.grid.filteringService.registerSVGIcons();
171-
this.init();
172-
this.sortingChanged.emit();
173-
174-
this.subscriptions = this.grid.columnPin.subscribe(() => {
175-
requestAnimationFrame(() => {
176-
if (!(this.cdr as ViewRef).destroyed) {
177-
this.cdr.detectChanges();
178-
}
179-
});
180-
});
181-
182-
this.subscriptions.add(this.grid.columnVisibilityChanged.subscribe(() => this.detectChanges()));
183-
this.subscriptions.add(this.grid.sortingExpressionsChange.subscribe(() => this.sortingChanged.emit()));
184-
this.subscriptions.add(this.grid.filteringExpressionsTreeChange.subscribe(() => this.init()));
185-
this.subscriptions.add(this.grid.columnMovingEnd.subscribe(() => this.cdr.markForCheck()));
169+
if (value) {
170+
this._column = value;
171+
this.columnChange.emit(this._column);
172+
if (this.inline) {
173+
// In case external filtering
174+
this.populateData();
175+
}
186176
}
187177
}
188178

@@ -326,6 +316,16 @@ export class IgxGridExcelStyleFilteringComponent extends BaseFilteringComponent
326316
this.inline = false;
327317
this.column = column;
328318
this.overlayService = overlayService;
319+
320+
}
321+
322+
/**
323+
* @hidden @internal
324+
*/
325+
public populateData() {
326+
if (this.column) {
327+
this.afterColumnChange();
328+
}
329329
if (this._originalDisplay) {
330330
this.element.nativeElement.style.display = this._originalDisplay;
331331
}
@@ -421,6 +421,34 @@ export class IgxGridExcelStyleFilteringComponent extends BaseFilteringComponent
421421
return this.computedStyles?.getPropertyValue('--component-size');
422422
}
423423

424+
protected afterColumnChange() {
425+
this.listData = new Array<FilterListItem>();
426+
this.subscriptions?.unsubscribe();
427+
428+
if (this._column) {
429+
this.grid.filteringService.registerSVGIcons();
430+
this.init();
431+
this.sortingChanged.emit();
432+
433+
this.subscriptions = this.grid.columnPin.subscribe(() => {
434+
requestAnimationFrame(() => {
435+
if (!(this.cdr as ViewRef).destroyed) {
436+
this.cdr.detectChanges();
437+
}
438+
});
439+
});
440+
441+
this.subscriptions.add(this.grid.columnVisibilityChanged.subscribe(() => this.detectChanges()));
442+
this.subscriptions.add(this.grid.sortingExpressionsChange.subscribe(() => this.sortingChanged.emit()));
443+
this.subscriptions.add(this.grid.filteringExpressionsTreeChange.subscribe(() => {
444+
this.expressionsList = new Array<ExpressionUI>();
445+
generateExpressionsList(this.column.filteringExpressionsTree, this.grid.filteringLogic, this.expressionsList);
446+
this.cdr.detectChanges();
447+
}));
448+
this.subscriptions.add(this.grid.columnMovingEnd.subscribe(() => this.cdr.markForCheck()));
449+
}
450+
}
451+
424452
private init() {
425453
this.expressionsList = new Array<ExpressionUI>();
426454
generateExpressionsList(this.column.filteringExpressionsTree, this.grid.filteringLogic, this.expressionsList);
@@ -510,12 +538,6 @@ export class IgxGridExcelStyleFilteringComponent extends BaseFilteringComponent
510538
private renderValues() {
511539
this.filterValues = this.generateFilterValues();
512540
this.generateListData();
513-
this.expressionsList.forEach(expr => {
514-
if (this.column.dataType === GridColumnDataType.String && this.column.filteringIgnoreCase
515-
&& expr.expression.searchVal && expr.expression.searchVal instanceof Set) {
516-
this.modifyExpression(expr);
517-
}
518-
});
519541
}
520542

521543
private generateFilterValues() {
@@ -546,16 +568,6 @@ export class IgxGridExcelStyleFilteringComponent extends BaseFilteringComponent
546568
return filterValues;
547569
}
548570

549-
private modifyExpression(expr: ExpressionUI) {
550-
const lowerCaseFilterValues = new Set(Array.from(expr.expression.searchVal).map((value: string) => value.toLowerCase()));
551-
552-
this.grid.data.forEach(item => {
553-
if (typeof item[this.column.field] === "string" && lowerCaseFilterValues.has(item[this.column.field]?.toLowerCase())) {
554-
expr.expression.searchVal.add(item[this.column.field]);
555-
}
556-
});
557-
}
558-
559571
private generateListData() {
560572
this.listData = new Array<FilterListItem>();
561573
const shouldUpdateSelection = this.areExpressionsSelectable();

0 commit comments

Comments
 (0)