Skip to content

Commit 406d91f

Browse files
Merge branch '17.2.x' into ganastasov/fix-14579-17.2.x
2 parents b4defff + 884f73f commit 406d91f

File tree

3 files changed

+128
-20
lines changed

3 files changed

+128
-20
lines changed

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

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ import {
1515
IgxGridAdvancedFilteringComponent,
1616
IgxGridExternalAdvancedFilteringComponent,
1717
IgxGridAdvancedFilteringBindingComponent,
18-
IgxGridAdvancedFilteringOverlaySettingsComponent
18+
IgxGridAdvancedFilteringOverlaySettingsComponent,
19+
IgxGridAdvancedFilteringDynamicColumnsComponent
1920
} from '../../test-utils/grid-samples.spec';
2021
import { ControlsFunction } from '../../test-utils/controls-functions.spec';
2122
import { FormattedValuesFilteringStrategy } from '../../data-operations/filtering-strategy';
2223
import { IgxHierGridExternalAdvancedFilteringComponent } from '../../test-utils/hierarchical-grid-components.spec';
2324
import { IgxHierarchicalGridComponent } from '../hierarchical-grid/public_api';
2425
import { IFilteringEventArgs } from '../public_api';
26+
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
2527

2628
const ADVANCED_FILTERING_OPERATOR_LINE_AND_CSS_CLASS = 'igx-filter-tree__line--and';
2729
const ADVANCED_FILTERING_OPERATOR_LINE_OR_CSS_CLASS = 'igx-filter-tree__line--or';
@@ -38,7 +40,8 @@ describe('IgxGrid - Advanced Filtering #grid - ', () => {
3840
IgxGridAdvancedFilteringComponent,
3941
IgxGridExternalAdvancedFilteringComponent,
4042
IgxGridAdvancedFilteringBindingComponent,
41-
IgxHierGridExternalAdvancedFilteringComponent
43+
IgxHierGridExternalAdvancedFilteringComponent,
44+
IgxGridAdvancedFilteringDynamicColumnsComponent
4245
]
4346
});
4447
}));
@@ -2048,6 +2051,78 @@ describe('IgxGrid - Advanced Filtering #grid - ', () => {
20482051
expect(rows.length).toEqual(1, 'Wrong filtered rows count');
20492052
}));
20502053

2054+
it('should handle advanced filtering correctly when grid columns and data are dynamically changed', fakeAsync(() => {
2055+
const fixture = TestBed.createComponent(IgxGridAdvancedFilteringDynamicColumnsComponent);
2056+
grid = fixture.componentInstance.grid;
2057+
fixture.detectChanges();
2058+
2059+
expect(grid.filteredData).toBeNull();
2060+
expect(grid.rowList.length).toBe(8);
2061+
expect(GridFunctions.getCurrentCellFromGrid(grid, 0, 1).value).toBe('Ignite UI for JavaScript');
2062+
expect(GridFunctions.getCurrentCellFromGrid(grid, 1, 1).value).toBe('NetAdvantage');
2063+
2064+
// Open Advanced Filtering dialog
2065+
GridFunctions.clickAdvancedFilteringButton(fixture);
2066+
fixture.detectChanges();
2067+
2068+
// Click the initial 'Add And Group' button
2069+
GridFunctions.clickAdvancedFilteringInitialAddGroupButton(fixture, 0);
2070+
tick(100);
2071+
fixture.detectChanges();
2072+
2073+
// Populate edit inputs
2074+
selectColumnInEditModeExpression(fixture, 1);
2075+
selectOperatorInEditModeExpression(fixture, 2);
2076+
const input = GridFunctions.getAdvancedFilteringValueInput(fixture).querySelector('input');
2077+
UIInteractions.clickAndSendInputElementValue(input, 'ign', fixture);
2078+
2079+
// Commit the populated expression
2080+
GridFunctions.clickAdvancedFilteringExpressionCommitButton(fixture);
2081+
fixture.detectChanges();
2082+
2083+
// Apply the filters
2084+
GridFunctions.clickAdvancedFilteringApplyButton(fixture);
2085+
fixture.detectChanges();
2086+
2087+
// Verify the filter results
2088+
expect(grid.filteredData.length).toEqual(2);
2089+
expect(grid.rowList.length).toBe(2);
2090+
expect(GridFunctions.getCurrentCellFromGrid(grid, 0, 1).value).toBe('Ignite UI for JavaScript');
2091+
expect(GridFunctions.getCurrentCellFromGrid(grid, 1, 1).value).toBe('Ignite UI for Angular');
2092+
2093+
// Change the grid's columns collection
2094+
fixture.componentInstance.columns = [
2095+
{ field: 'ID', header: 'ID', width: '200px', type: 'string' },
2096+
{ field: 'CompanyName', header: 'Company Name', width: '200px', type: 'string'},
2097+
{ field: 'ContactName', header: 'Contact Name', width: '200px', type: 'string' },
2098+
{ field: 'ContactTitle', header: 'Contact Title', width: '200px', type: 'string' },
2099+
{ field: 'City', header: 'City', width: '200px', type: 'string' },
2100+
{ field: 'Country', header: 'Country', width: '200px', type: 'string' },
2101+
];
2102+
fixture.detectChanges();
2103+
flush();
2104+
2105+
// Change the grid's data collection
2106+
grid.data = SampleTestData.contactInfoDataFull();
2107+
fixture.detectChanges();
2108+
flush();
2109+
2110+
// Check for error messages in the console
2111+
const consoleSpy = spyOn(console, 'error');
2112+
2113+
// Open Advanced Filtering dialog
2114+
GridFunctions.clickAdvancedFilteringButton(fixture);
2115+
fixture.detectChanges();
2116+
flush();
2117+
2118+
// Verify the filters are cleared
2119+
expect(grid.filteredData).toEqual([]);
2120+
expect(grid.rowList.length).toBe(0);
2121+
2122+
// Check for error messages in the console
2123+
expect(consoleSpy).not.toHaveBeenCalled();
2124+
}));
2125+
20512126
describe('Context Menu - ', () => {
20522127
it('Should discard added group when clicking its operator line without having a single expression.', fakeAsync(() => {
20532128
// Open Advanced Filtering dialog.

projects/igniteui-angular/src/lib/query-builder/query-builder.component.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -991,31 +991,33 @@ export class IgxQueryBuilderComponent extends DisplayDensityBase implements Afte
991991
this.currentGroup = groupItem;
992992
}
993993

994-
private createExpressionGroupItem(expressionTree: IExpressionTree, parent?: ExpressionGroupItem): ExpressionGroupItem {
995-
let groupItem: ExpressionGroupItem;
996-
if (expressionTree) {
997-
groupItem = new ExpressionGroupItem(expressionTree.operator, parent);
998-
999-
for (const expr of expressionTree.filteringOperands) {
1000-
if (expr instanceof FilteringExpressionsTree) {
1001-
groupItem.children.push(this.createExpressionGroupItem(expr, groupItem));
1002-
} else {
1003-
const filteringExpr = expr as IFilteringExpression;
1004-
const exprCopy: IFilteringExpression = {
1005-
fieldName: filteringExpr.fieldName,
1006-
condition: filteringExpr.condition,
1007-
searchVal: filteringExpr.searchVal,
1008-
ignoreCase: filteringExpr.ignoreCase
1009-
};
994+
private createExpressionGroupItem(expressionTree: IExpressionTree, parent?: ExpressionGroupItem): ExpressionGroupItem | null {
995+
if (!expressionTree) {
996+
return null;
997+
}
998+
999+
const groupItem = new ExpressionGroupItem(expressionTree.operator, parent);
1000+
1001+
for (const expr of expressionTree.filteringOperands) {
1002+
if (expr instanceof FilteringExpressionsTree) {
1003+
const childGroup = this.createExpressionGroupItem(expr, groupItem);
1004+
if (childGroup) {
1005+
groupItem.children.push(childGroup);
1006+
}
1007+
} else {
1008+
const filteringExpr = expr as IFilteringExpression;
1009+
const field = this.fields.find(el => el.field === filteringExpr.fieldName);
1010+
1011+
if (field) {
1012+
const exprCopy: IFilteringExpression = { ...filteringExpr };
10101013
const operandItem = new ExpressionOperandItem(exprCopy, groupItem);
1011-
const field = this.fields.find(el => el.field === filteringExpr.fieldName);
10121014
operandItem.fieldLabel = field.label || field.header || field.field;
10131015
groupItem.children.push(operandItem);
10141016
}
10151017
}
10161018
}
10171019

1018-
return groupItem;
1020+
return groupItem.children.length > 0 ? groupItem : null;
10191021
}
10201022

10211023
private createExpressionTreeFromGroupItem(groupItem: ExpressionGroupItem): FilteringExpressionsTree {

projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,37 @@ export class IgxGridAdvancedFilteringComponent extends BasicGridComponent {
11741174
}
11751175
}
11761176

1177+
@Component({
1178+
template: `<igx-grid [data]="data" height="500px" [allowAdvancedFiltering]="true">
1179+
<igx-grid-toolbar></igx-grid-toolbar>
1180+
<igx-column *ngFor="let c of columns"
1181+
[field]="c.field"
1182+
[header]="c.header"
1183+
[width]="c.width"
1184+
[filterable]="true"
1185+
[dataType]="c.type">
1186+
</igx-column>
1187+
</igx-grid>`,
1188+
standalone: true,
1189+
imports: [NgFor, IgxGridComponent, IgxColumnComponent, IgxGridToolbarComponent]
1190+
})
1191+
export class IgxGridAdvancedFilteringDynamicColumnsComponent extends BasicGridComponent {
1192+
public override data = [];
1193+
public columns = [];
1194+
1195+
public ngOnInit(): void {
1196+
this.columns = [
1197+
{ field: 'ID', header: 'HeaderID', width: '100px', type: 'number' },
1198+
{ field: 'ProductName', header: 'Product Name', width: '200px', type: 'string'},
1199+
{ field: 'Downloads', header: 'Downloads', width: '100px', type: 'number' },
1200+
{ field: 'Released', header: 'Released', width: '100px', type: 'boolean' },
1201+
{ field: 'ReleaseDate', header: 'Release Date', width: '200px', type: 'date' },
1202+
{ field: 'AnotherField', header: 'Another Field', width: '200px', type: 'string' },
1203+
];
1204+
this.data = SampleTestData.excelFilteringData();
1205+
}
1206+
}
1207+
11771208
@Component({
11781209
template: `<igx-grid [data]="data" height="500px" [allowAdvancedFiltering]="true">
11791210
<igx-grid-toolbar>

0 commit comments

Comments
 (0)