Skip to content

Commit 6c3482b

Browse files
authored
Merge pull request #9297 from IgniteUI/dmdimitrov/fix-9050-10.2.x
fix(hierarchical-grid): fixed row island filtering - 10.2.x
2 parents 38f4531 + ddb8292 commit 6c3482b

File tree

6 files changed

+150
-104
lines changed

6 files changed

+150
-104
lines changed

projects/igniteui-angular/src/lib/grids/api.service.ts

Lines changed: 0 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@ import { Injectable } from '@angular/core';
22
import { Subject } from 'rxjs';
33
import { cloneArray, isEqual, reverseMapper, mergeObjects } from '../core/utils';
44
import { DataUtil, DataType } from '../data-operations/data-util';
5-
import { IFilteringExpression } from '../data-operations/filtering-expression.interface';
65
import { ISortingExpression, SortingDirection } from '../data-operations/sorting-expression.interface';
76
import { IgxGridCellComponent } from './cell.component';
87
import { IgxGridBaseDirective } from './grid-base.directive';
98
import { IgxRowDirective } from './row.directive';
10-
import { IFilteringOperation } from '../data-operations/filtering-condition';
11-
import { IFilteringExpressionsTree, FilteringExpressionsTree } from '../data-operations/filtering-expressions-tree';
129
import { Transaction, TransactionType, State } from '../services/transaction/transaction';
1310
import { IgxCell, IgxRow } from './selection/selection.service';
1411
import { GridType } from './common/grid.interface';
@@ -328,61 +325,6 @@ export class GridBaseAPIService<T extends IgxGridBaseDirective & GridType> {
328325
this.grid.sortingExpressions = sortingState;
329326
}
330327

331-
public filter(fieldName: string, term, conditionOrExpressionsTree: IFilteringOperation | IFilteringExpressionsTree,
332-
ignoreCase: boolean) {
333-
const grid = this.grid;
334-
const filteringTree = grid.filteringExpressionsTree;
335-
this.grid.endEdit(false);
336-
337-
if (grid.paging) {
338-
grid.page = 0;
339-
}
340-
341-
const fieldFilterIndex = filteringTree.findIndex(fieldName);
342-
if (fieldFilterIndex > -1) {
343-
filteringTree.filteringOperands.splice(fieldFilterIndex, 1);
344-
}
345-
346-
this.prepare_filtering_expression(filteringTree, fieldName, term, conditionOrExpressionsTree, ignoreCase, fieldFilterIndex);
347-
grid.filteringExpressionsTree = filteringTree;
348-
}
349-
350-
public filter_global(term, condition, ignoreCase) {
351-
if (!condition) {
352-
return;
353-
}
354-
355-
const grid = this.grid;
356-
const filteringTree = grid.filteringExpressionsTree;
357-
grid.endEdit(false);
358-
if (grid.paging) {
359-
grid.page = 0;
360-
}
361-
362-
filteringTree.filteringOperands = [];
363-
for (const column of grid.columns) {
364-
this.prepare_filtering_expression(filteringTree, column.field, term,
365-
condition, ignoreCase || column.filteringIgnoreCase);
366-
}
367-
368-
grid.filteringExpressionsTree = filteringTree;
369-
}
370-
371-
public clear_filter(fieldName: string) {
372-
const grid = this.grid;
373-
grid.endEdit(false);
374-
const filteringState = grid.filteringExpressionsTree;
375-
const index = filteringState.findIndex(fieldName);
376-
377-
if (index > -1) {
378-
filteringState.filteringOperands.splice(index, 1);
379-
} else if (!fieldName) {
380-
filteringState.filteringOperands = [];
381-
}
382-
383-
grid.filteringExpressionsTree = filteringState;
384-
}
385-
386328
public clear_sort(fieldName: string) {
387329
const sortingState = this.grid.sortingExpressions;
388330
const index = sortingState.findIndex((expr) => expr.fieldName === fieldName);
@@ -392,34 +334,6 @@ export class GridBaseAPIService<T extends IgxGridBaseDirective & GridType> {
392334
}
393335
}
394336

395-
protected prepare_filtering_expression(filteringState: IFilteringExpressionsTree, fieldName: string, searchVal,
396-
conditionOrExpressionsTree: IFilteringOperation | IFilteringExpressionsTree, ignoreCase: boolean, insertAtIndex = -1) {
397-
398-
let newExpressionsTree;
399-
const oldExpressionsTreeIndex = filteringState.findIndex(fieldName);
400-
const expressionsTree = conditionOrExpressionsTree instanceof FilteringExpressionsTree ?
401-
conditionOrExpressionsTree as IFilteringExpressionsTree : null;
402-
const condition = conditionOrExpressionsTree instanceof FilteringExpressionsTree ?
403-
null : conditionOrExpressionsTree as IFilteringOperation;
404-
const newExpression: IFilteringExpression = { fieldName, searchVal, condition, ignoreCase };
405-
406-
if (oldExpressionsTreeIndex === -1) {
407-
// no expressions tree found for this field
408-
if (expressionsTree) {
409-
if (insertAtIndex > -1) {
410-
filteringState.filteringOperands.splice(insertAtIndex, 0, expressionsTree);
411-
} else {
412-
filteringState.filteringOperands.push(expressionsTree);
413-
}
414-
} else if (condition) {
415-
// create expressions tree for this field and add the new expression to it
416-
newExpressionsTree = new FilteringExpressionsTree(filteringState.operator, fieldName);
417-
newExpressionsTree.filteringOperands.push(newExpression);
418-
filteringState.filteringOperands.push(newExpressionsTree);
419-
}
420-
}
421-
}
422-
423337
protected prepare_sorting_expression(stateCollections: Array<Array<any>>, expression: ISortingExpression) {
424338
if (expression.dir === SortingDirection.None) {
425339
stateCollections.forEach(state => {
@@ -629,5 +543,4 @@ export class GridBaseAPIService<T extends IgxGridBaseDirective & GridType> {
629543
private isToggleKey(key: string): boolean {
630544
return ROW_COLLAPSE_KEYS.has(key) || ROW_EXPAND_KEYS.has(key);
631545
}
632-
633546
}

projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts

Lines changed: 92 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ import { takeUntil, first } from 'rxjs/operators';
77
import { IForOfState } from '../../directives/for-of/for_of.directive';
88
import { IgxColumnComponent } from '../columns/column.component';
99
import { IFilteringOperation } from '../../data-operations/filtering-condition';
10-
import { GridBaseAPIService } from '../api.service';
1110
import { IColumnResizeEventArgs } from '../common/events';
12-
import { GridType } from '../common/grid.interface';
1311
import { OverlaySettings, PositionSettings, VerticalAlignment } from '../../services/overlay/utilities';
1412
import { IgxOverlayService } from '../../services/overlay/overlay';
1513
import { useAnimation } from '@angular/animations';
16-
import { fadeIn, fadeOut } from '../../animations/main';
14+
import { fadeIn } from '../../animations/main';
1715
import { ExcelStylePositionStrategy } from './excel-style/excel-style-position-strategy';
1816
import { AbsoluteScrollStrategy } from '../../services/overlay/scroll/absolute-scroll-strategy';
1917
import { IgxGridExcelStyleFilteringComponent } from './excel-style/grid.excel-style-filtering.component';
@@ -56,7 +54,7 @@ export class IgxFilteringService implements OnDestroy {
5654
public activeFilterCell = 0;
5755
grid: IgxGridBaseDirective;
5856

59-
constructor(private gridAPI: GridBaseAPIService<IgxGridBaseDirective & GridType>, private _moduleRef: NgModuleRef<any>,
57+
constructor(private _moduleRef: NgModuleRef<any>,
6058
private iconService: IgxIconService, private _overlayService: IgxOverlayService) {}
6159

6260
ngOnDestroy(): void {
@@ -200,41 +198,61 @@ export class IgxFilteringService implements OnDestroy {
200198
*/
201199
public filter(field: string, value: any, conditionOrExpressionTree?: IFilteringOperation | IFilteringExpressionsTree,
202200
ignoreCase?: boolean) {
203-
const col = this.gridAPI.get_column_by_name(field);
201+
const col = this.grid.getColumnByName(field);
204202
const filteringIgnoreCase = ignoreCase || (col ? col.filteringIgnoreCase : false);
205203

206204
if (conditionOrExpressionTree) {
207-
this.gridAPI.filter(field, value, conditionOrExpressionTree, filteringIgnoreCase);
205+
this.filter_internal(field, value, conditionOrExpressionTree, filteringIgnoreCase);
208206
} else {
209207
const expressionsTreeForColumn = this.grid.filteringExpressionsTree.find(field);
210208
if (!expressionsTreeForColumn) {
211209
throw new Error('Invalid condition or Expression Tree!');
212210
} else if (expressionsTreeForColumn instanceof FilteringExpressionsTree) {
213-
this.gridAPI.filter(field, value, expressionsTreeForColumn, filteringIgnoreCase);
211+
this.filter_internal(field, value, expressionsTreeForColumn, filteringIgnoreCase );
214212
} else {
215213
const expressionForColumn = expressionsTreeForColumn as IFilteringExpression;
216-
this.gridAPI.filter(field, value, expressionForColumn.condition, filteringIgnoreCase);
214+
this.filter_internal(field, value, expressionForColumn.condition, filteringIgnoreCase );
217215
}
218216
}
219217
const eventArgs = this.grid.filteringExpressionsTree.find(field) as FilteringExpressionsTree;
220218
// Wait for the change detection to update filtered data through the pipes and then emit the event.
221219
requestAnimationFrame(() => this.grid.onFilteringDone.emit(eventArgs));
222220
}
223221

222+
public filter_global(term, condition, ignoreCase) {
223+
if (!condition) {
224+
return;
225+
}
226+
227+
const grid = this.grid;
228+
const filteringTree = grid.filteringExpressionsTree;
229+
grid.endEdit(false);
230+
if (grid.paging) {
231+
grid.page = 0;
232+
}
233+
234+
filteringTree.filteringOperands = [];
235+
for (const column of grid.columns) {
236+
this.prepare_filtering_expression(filteringTree, column.field, term,
237+
condition, ignoreCase || column.filteringIgnoreCase);
238+
}
239+
240+
grid.filteringExpressionsTree = filteringTree;
241+
}
242+
224243
/**
225244
* Clears the filter of a given column if name is provided. Otherwise clears the filters of all columns.
226245
*/
227246
public clearFilter(field: string): void {
228247
if (field) {
229-
const column = this.gridAPI.get_column_by_name(field);
248+
const column = this.grid.getColumnByName(field);
230249
if (!column) {
231250
return;
232251
}
233252
}
234253

235254
this.isFiltering = true;
236-
237-
this.gridAPI.clear_filter(field);
255+
this.clear_filter(field);
238256

239257
// Wait for the change detection to update filtered data through the pipes and then emit the event.
240258
requestAnimationFrame(() => this.grid.onFilteringDone.emit(null));
@@ -252,11 +270,26 @@ export class IgxFilteringService implements OnDestroy {
252270
this.isFiltering = false;
253271
}
254272

273+
public clear_filter(fieldName: string) {
274+
const grid = this.grid;
275+
grid.endEdit(false);
276+
const filteringState = grid.filteringExpressionsTree;
277+
const index = filteringState.findIndex(fieldName);
278+
279+
if (index > -1) {
280+
filteringState.filteringOperands.splice(index, 1);
281+
} else if (!fieldName) {
282+
filteringState.filteringOperands = [];
283+
}
284+
285+
grid.filteringExpressionsTree = filteringState;
286+
}
287+
255288
/**
256289
* Filters all the `IgxColumnComponent` in the `IgxGridComponent` with the same condition.
257290
*/
258291
public filterGlobal(value: any, condition, ignoreCase?) {
259-
this.gridAPI.filter_global(value, condition, ignoreCase);
292+
this.filter_global(value, condition, ignoreCase);
260293

261294
// Wait for the change detection to update filtered data through the pipes and then emit the event.
262295
requestAnimationFrame(() => this.grid.onFilteringDone.emit(this.grid.filteringExpressionsTree));
@@ -435,6 +468,53 @@ export class IgxFilteringService implements OnDestroy {
435468
return this.grid.filteredData;
436469
}
437470

471+
private filter_internal(fieldName: string, term, conditionOrExpressionsTree: IFilteringOperation | IFilteringExpressionsTree,
472+
ignoreCase: boolean) {
473+
const grid = this.grid;
474+
const filteringTree = grid.filteringExpressionsTree;
475+
this.grid.endEdit(false);
476+
477+
if (grid.paging) {
478+
grid.page = 0;
479+
}
480+
481+
const fieldFilterIndex = filteringTree.findIndex(fieldName);
482+
if (fieldFilterIndex > -1) {
483+
filteringTree.filteringOperands.splice(fieldFilterIndex, 1);
484+
}
485+
486+
this.prepare_filtering_expression(filteringTree, fieldName, term, conditionOrExpressionsTree, ignoreCase, fieldFilterIndex);
487+
grid.filteringExpressionsTree = filteringTree;
488+
}
489+
490+
private prepare_filtering_expression(filteringState: IFilteringExpressionsTree, fieldName: string, searchVal,
491+
conditionOrExpressionsTree: IFilteringOperation | IFilteringExpressionsTree, ignoreCase: boolean, insertAtIndex = -1) {
492+
493+
let newExpressionsTree;
494+
const oldExpressionsTreeIndex = filteringState.findIndex(fieldName);
495+
const expressionsTree = conditionOrExpressionsTree instanceof FilteringExpressionsTree ?
496+
conditionOrExpressionsTree as IFilteringExpressionsTree : null;
497+
const condition = conditionOrExpressionsTree instanceof FilteringExpressionsTree ?
498+
null : conditionOrExpressionsTree as IFilteringOperation;
499+
const newExpression: IFilteringExpression = { fieldName, searchVal, condition, ignoreCase };
500+
501+
if (oldExpressionsTreeIndex === -1) {
502+
// no expressions tree found for this field
503+
if (expressionsTree) {
504+
if (insertAtIndex > -1) {
505+
filteringState.filteringOperands.splice(insertAtIndex, 0, expressionsTree);
506+
} else {
507+
filteringState.filteringOperands.push(expressionsTree);
508+
}
509+
} else if (condition) {
510+
// create expressions tree for this field and add the new expression to it
511+
newExpressionsTree = new FilteringExpressionsTree(filteringState.operator, fieldName);
512+
newExpressionsTree.filteringOperands.push(newExpression);
513+
filteringState.filteringOperands.push(newExpressionsTree);
514+
}
515+
}
516+
}
517+
438518
private isFilteringTreeComplex(expressions: IFilteringExpressionsTree | IFilteringExpression): boolean {
439519
if (!expressions) {
440520
return false;

projects/igniteui-angular/src/lib/grids/grid-base.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5221,7 +5221,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements
52215221
this.gridAPI.clear_groupby(record.item.field);
52225222

52235223
// Clear Filtering
5224-
this.gridAPI.clear_filter(record.item.field);
5224+
this.filteringService.clear_filter(record.item.field);
52255225

52265226
// Close filter row
52275227
if (this.filteringService.isFilterRowVisible

projects/igniteui-angular/src/lib/grids/grid/grid-cell-editing.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,7 @@ describe('IgxGrid - Cell Editing #grid', () => {
11041104

11051105
grid.filter('fullName', 'Al', IgxStringFilteringOperand.instance().condition('equals'));
11061106
fixture.detectChanges();
1107-
cell.gridAPI.clear_filter('fullName');
1107+
grid.clearFilter('fullName');
11081108
fixture.detectChanges();
11091109

11101110
cell = grid.getCellByColumn(0, 'fullName');

projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,57 @@ describe('IgxHierarchicalGrid Row Islands #hGrid', () => {
720720
expect(ri1.onCellClick.emit).toHaveBeenCalledTimes(1);
721721
expect(ri1.onCellClick.emit).toHaveBeenCalledWith(args);
722722
});
723+
724+
it('should filter correctly on row island',
725+
fakeAsync(() => { /** height/width setter rAF + row toggle rAF */
726+
const uniqueData = [
727+
{
728+
ID: 1,
729+
ProductName : 'Parent Name',
730+
childData: [
731+
{
732+
ID: 11,
733+
ProductName : 'Child11 ProductName'
734+
},
735+
{
736+
ID: 12,
737+
ProductName : 'Child12 ProductName'
738+
}
739+
],
740+
childData2: [
741+
{
742+
ID: 21,
743+
Col1: 'Child21 Col1',
744+
Col2: 'Child21 Col2',
745+
Col3: 'Child21 Col3'
746+
},
747+
{
748+
ID: 22,
749+
Col1: 'Child22 Col1',
750+
Col2: 'Child22 Col2',
751+
Col3: 'Child22 Col3'
752+
}
753+
]
754+
}
755+
];
756+
fixture.componentInstance.data = uniqueData;
757+
fixture.detectChanges();
758+
759+
const rowIsland1 = fixture.componentInstance.rowIsland1 as IgxRowIslandComponent;
760+
rowIsland1.filter('ProductName', 'Child12', IgxStringFilteringOperand.instance().condition('contains'), true);
761+
762+
const row = hierarchicalGrid.getRowByIndex(0) as IgxHierarchicalRowComponent;
763+
UIInteractions.simulateClickAndSelectEvent(row.expander);
764+
tick();
765+
fixture.detectChanges();
766+
767+
const childGrids = fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
768+
const childGrid1 = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;
769+
expect(childGrid1.data.length).toEqual(2);
770+
expect(childGrid1.filteredData.length).toEqual(1);
771+
expect(childGrid1.rowList.length).toEqual(1);
772+
expect(childGrid1.getCellByColumn(0, 'ProductName').nativeElement.innerText).toEqual('Child12 ProductName');
773+
}));
723774
});
724775

725776
describe('IgxHierarchicalGrid Children Sizing #hGrid', () => {
@@ -1384,12 +1435,12 @@ export class IgxHierarchicalGridTestBaseComponent {
13841435
// 3 level hierarchy
13851436
this.data = this.generateDataUneven(20, 3);
13861437
}
1387-
generateDataUneven(count: number, level: number, parendID: string = null) {
1438+
generateDataUneven(count: number, level: number, parentID: string = null) {
13881439
const prods = [];
13891440
const currLevel = level;
13901441
let children;
13911442
for (let i = 0; i < count; i++) {
1392-
const rowID = parendID ? parendID + i : i.toString();
1443+
const rowID = parentID ? parentID + i : i.toString();
13931444
if (level > 0 ) {
13941445
// Have child grids for row with even id less rows by not multiplying by 2
13951446
children = this.generateDataUneven((i % 2 + 1) * Math.round(count / 3) , currLevel - 1, rowID);

0 commit comments

Comments
 (0)