diff --git a/CHANGELOG.md b/CHANGELOG.md index db4196e3639..86518547bd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes for each version of this project will be documented in this file. +## 21.2.0 + +### General +- `IgxHierarchicalGrid` + - **Deprecation** - `schema` input property has been deprecated and will be removed in a future version. + ## 21.1.0 ### New Features diff --git a/projects/igniteui-angular/grids/grid/src/grid-filtering-advanced.spec.ts b/projects/igniteui-angular/grids/grid/src/grid-filtering-advanced.spec.ts index 0c8c636f9b1..3a341336183 100644 --- a/projects/igniteui-angular/grids/grid/src/grid-filtering-advanced.spec.ts +++ b/projects/igniteui-angular/grids/grid/src/grid-filtering-advanced.spec.ts @@ -15,7 +15,7 @@ import { import { IgxHierarchicalGridExportComponent, IgxHierarchicalGridTestBaseComponent, IgxHierGridExternalAdvancedFilteringComponent } from '../../../test-utils/hierarchical-grid-components.spec'; import { SampleTestData } from '../../../test-utils/sample-test-data.spec'; import { By } from '@angular/platform-browser'; -import { IgxHGridRemoteOnDemandComponent, IgxHierarchicalGridMissingChildDataComponent } from '../../hierarchical-grid/src/hierarchical-grid.spec'; +import { IgxHGridRemoteOnDemandComponent, IgxHierarchicalGridMissingChildDataComponent, IgxHierarchicalGridToggleRIComponent } from '../../hierarchical-grid/src/hierarchical-grid.spec'; import { QueryBuilderFunctions } from '../../../query-builder/src/query-builder/query-builder-functions.spec'; import { IFilteringEventArgs, IgxGridNavigationService, IgxGridToolbarAdvancedFilteringComponent } from 'igniteui-angular/grids/core'; import { FilteringExpressionsTree, FilteringLogic, FormattedValuesFilteringStrategy, IGridResourceStrings, IgxNumberFilteringOperand, IgxStringFilteringOperand } from 'igniteui-angular/core'; @@ -1746,76 +1746,69 @@ describe('IgxGrid - Advanced Filtering #grid - ', () => { expect(hgrid.filteredData.length).toBe(5); })); - it('Should have proper fields in UI when schema is defined with load on demand.', fakeAsync(() => { - const fixture = TestBed.createComponent(IgxHGridRemoteOnDemandComponent); - const hierarchicalGrid = fixture.componentInstance.instance; + it('Should update root grid schema when row island is expanded.', fakeAsync(() => { + const fixture = TestBed.createComponent(IgxHierarchicalGridToggleRIComponent); + const hierarchicalGrid = fixture.componentInstance.hgrid; hierarchicalGrid.allowAdvancedFiltering = true; - hierarchicalGrid.schema = [ - { - name: 'rootLevel', - fields: [ - { field: 'ID', dataType: 'string' }, - { field: 'ChildLevels', dataType: 'number' }, - { field: 'ProductName', dataType: 'string' }, - { field: 'Col1', dataType: 'number' }, - { field: 'Col2', dataType: 'number' }, - { field: 'Col3', dataType: 'number' } - ], - childEntities: [ - { - name: 'childData', - fields: [ - { field: 'ID', dataType: 'string' }, - { field: 'ProductName', dataType: 'string' } - ], - childEntities: [ - { - name: 'childData2', - fields: [ - { field: 'ID', dataType: 'string' }, - { field: 'ProductName', dataType: 'string' } - ] - } - ] - } - ] - } - ] fixture.detectChanges(); - hierarchicalGrid.openAdvancedFilteringDialog(); - fixture.detectChanges(); + // Open advanced filtering dialog and create an 'In' condition. + const createInConditionAndGetReturnFields = () => { + // Open Advanced Filtering dialog. + hierarchicalGrid.openAdvancedFilteringDialog(); + fixture.detectChanges(); - // Click the initial 'Add Condition' button. - QueryBuilderFunctions.clickQueryBuilderInitialAddConditionBtn(fixture, 0); - tick(100); - fixture.detectChanges(); - // Populate edit inputs. - QueryBuilderFunctions.selectColumnInEditModeExpression(fixture, 0); // Select 'ID' column. - QueryBuilderFunctions.selectOperatorInEditModeExpression(fixture, 10); // Select 'In' operator. - tick(100); - fixture.detectChanges(); + // Click the initial 'Add Condition' button. + QueryBuilderFunctions.clickQueryBuilderInitialAddConditionBtn(fixture, 0); + tick(100); + fixture.detectChanges(); + // Populate edit inputs. + QueryBuilderFunctions.selectColumnInEditModeExpression(fixture, 0); // Select 'ID' column. + QueryBuilderFunctions.selectOperatorInEditModeExpression(fixture, 10); // Select 'In' operator. + tick(100); + fixture.detectChanges(); - const entityInputGroup = QueryBuilderFunctions.getQueryBuilderEntitySelect(fixture, 1).querySelector('input'); - expect(entityInputGroup.value).toBe('childData'); + // Verify entities + QueryBuilderFunctions.clickQueryBuilderEntitySelect(fixture, 1); + fixture.detectChanges(); + const queryBuilderElement: HTMLElement = fixture.debugElement.queryAll(By.css(`.${QueryBuilderSelectors.QUERY_BUILDER_TREE}`))[1].nativeElement; + let dropdownValues: string[] = QueryBuilderFunctions.getQueryBuilderSelectDropdownItems(queryBuilderElement).map((x: any) => x.innerText); + let expectedValues = ['childData']; + expect(dropdownValues).toEqual(expectedValues); - const fieldInputGroup = QueryBuilderFunctions.getQueryBuilderFieldsCombo(fixture, 1).querySelector('input'); - expect(fieldInputGroup.value).toBe('ID'); + // Verify return fields + QueryBuilderFunctions.clickQueryBuilderFieldsCombo(fixture, 1); + fixture.detectChanges(); + const innerQueryReturnFields = QueryBuilderFunctions.getQueryBuilderSelectDropdown(queryBuilderElement, 1); + + return innerQueryReturnFields; + }; + + let innerQueryReturnFields = createInConditionAndGetReturnFields(); + expect(innerQueryReturnFields).toBeNull(); - // Verify entities - QueryBuilderFunctions.clickQueryBuilderEntitySelect(fixture, 1); + // Close Advanced Filtering dialog. + hierarchicalGrid.closeAdvancedFilteringDialog(false); + tick(200); fixture.detectChanges(); - const queryBuilderElement: HTMLElement = fixture.debugElement.queryAll(By.css(`.${QueryBuilderSelectors.QUERY_BUILDER_TREE}`))[1].nativeElement; - let dropdownValues: string[] = QueryBuilderFunctions.getQueryBuilderSelectDropdownItems(queryBuilderElement).map((x: any) => x.innerText); - let expectedValues = ['childData']; - expect(dropdownValues).toEqual(expectedValues); - // Verify return fileds - QueryBuilderFunctions.clickQueryBuilderFieldsCombo(fixture, 1); + // Expand row island + const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as any; + UIInteractions.simulateClickAndSelectEvent(row.expander); fixture.detectChanges(); - dropdownValues = QueryBuilderFunctions.getQueryBuilderSelectDropdownItems(queryBuilderElement, 1).map((x: any) => x.innerText); - expectedValues = ['ID', 'ProductName']; - expect(dropdownValues).toEqual(expectedValues); + + // Open advanced filtering dialog and verify that schema is updated. + innerQueryReturnFields = createInConditionAndGetReturnFields(); + expect(innerQueryReturnFields).not.toBeNull(); + const items = Array.from(innerQueryReturnFields.querySelectorAll('.igx-drop-down__item')); + expect(items.length).toBe(7); + expect((items[0] as HTMLElement).innerText).toBe('ID'); + expect((items[1] as HTMLElement).innerText).toBe('ChildLevels'); + expect((items[2] as HTMLElement).innerText).toBe('ProductName'); + expect((items[3] as HTMLElement).innerText).toBe('Col1'); + expect((items[4] as HTMLElement).innerText).toBe('Col2'); + expect((items[5] as HTMLElement).innerText).toBe('Col3'); + expect((items[6] as HTMLElement).innerText).toBe('childData2'); })); it('Should correctly change resource strings for hierarchical Advanced Filtering dialog.', fakeAsync(() => { diff --git a/projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-grid.component.ts b/projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-grid.component.ts index ba34f9ad9de..53ae2d4fcfd 100644 --- a/projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-grid.component.ts +++ b/projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-grid.component.ts @@ -562,11 +562,10 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti * const schema = this.grid.schema; * this.grid.schema = [{ name: 'Products', fields: [...], childEntities: [...] }]; * ``` + * @deprecated in version 20.2.0. */ @Input() - public set schema(entities: EntityType[]) { - this._hGridSchema = entities; - } + public set schema(entities: EntityType[]) {} /* blazorSuppress */ public get schema() { @@ -679,6 +678,10 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti this.batchEditing = val; }); } + this.columnsAutogenerated.subscribe((e) => { + this.updateRootGridSchema(e); + }); + super.ngOnInit(); } @@ -1232,7 +1235,7 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti } private generateSchema() { - const filterableFields = this.columns.filter((column) => !column.columnGroup && column.filterable); + const filterableFields: FieldType[] = this.columns.filter((column) => !column.columnGroup && column.filterable); let entities: EntityType[]; if(filterableFields.length !== 0) { @@ -1242,6 +1245,7 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti fields: filterableFields.map(f => ({ field: f.field, dataType: f.dataType, + label: f.label, header: f.header, editorOptions: f.editorOptions, filters: f.filters, @@ -1253,9 +1257,7 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti ]; entities[0].childEntities = this.childLayoutList.reduce((acc, rowIsland) => { - const childFirstRowData = this.data?.length > 0 && this.data[0][rowIsland.key]?.length > 0 ? - this.data[0][rowIsland.key][0] : null; - return acc.concat(this.generateChildEntity(rowIsland, childFirstRowData)); + return acc.concat(this.generateChildEntity(rowIsland)); } , []); } @@ -1263,34 +1265,54 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti return entities; } - private generateChildEntity(rowIsland: IgxRowIslandComponent, firstRowData: any[]): EntityType { + private updateRootGridSchema(event: any) { + const schema = (this.rootGrid as IgxHierarchicalGridComponent).schema; + if (!schema || schema.length === 0) { + return; + } + + let path = []; + let parentIsland = this.parentIsland; + while (parentIsland) { + path.push(parentIsland.key); + parentIsland = parentIsland.parentIsland; + } + + path.reverse(); + if (path.length > 0) { + let childEntity = schema[0]; + for (let i = 0; i < path.length; i++) { + childEntity = childEntity.childEntities.find(e => e.name === path[i]); + } + + if (childEntity) { + childEntity.fields = event.columns.filter((column) => !column.columnGroup && column.filterable) + .map(f => ({ + field: f.field, + dataType: f.dataType, + label: f.label, + header: f.header, + editorOptions: f.editorOptions, + filters: f.filters, + pipeArgs: f.pipeArgs, + defaultTimeFormat: f.defaultTimeFormat, + defaultDateTimeFormat: f.defaultDateTimeFormat + })) as FieldType[]; + } + } + } + + private generateChildEntity(rowIsland: IgxRowIslandComponent): EntityType { const entityName = rowIsland.key; let fields = []; let childEntities; - if (!rowIsland.autoGenerate) { + if (rowIsland.childColumns?.length > 0) { fields = flatten(rowIsland.childColumns.toArray()).filter(col => col.field) .map(f => ({ field: f.field, dataType: f.dataType })) as FieldType[]; - } else if (firstRowData) { - const rowIslandFields = Object.keys(firstRowData).map(key => { - if (firstRowData[key] instanceof Array) { - return null; - } - - return { - field: key, - dataType: this.resolveDataTypes(firstRowData[key]) - } - }); - fields = rowIslandFields.filter(f => f !== null) as FieldType[]; } const rowIslandChildEntities = rowIsland.childLayoutList.reduce((acc, childRowIsland) => { - if (!firstRowData) { - return null; - } - const childFirstRowData = firstRowData.length > 0 && firstRowData[childRowIsland.key]?.length > 0 ? - firstRowData[childRowIsland.key][0] : null; - return acc.concat(this.generateChildEntity(childRowIsland, childFirstRowData)); + return acc.concat(this.generateChildEntity(childRowIsland)); }, []); if (rowIslandChildEntities?.length > 0) { diff --git a/projects/igniteui-angular/query-builder/src/query-builder/query-builder-tree.component.ts b/projects/igniteui-angular/query-builder/src/query-builder/query-builder-tree.component.ts index 729b6ce9bb9..331ab32397c 100644 --- a/projects/igniteui-angular/query-builder/src/query-builder/query-builder-tree.component.ts +++ b/projects/igniteui-angular/query-builder/src/query-builder/query-builder-tree.component.ts @@ -1428,7 +1428,7 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy { * @hidden @internal */ public getFormat(field: string) { - return this.fields?.find(el => el.field === field).pipeArgs.format; + return this.fields?.find(el => el.field === field)?.pipeArgs.format; } /**