diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fe5277e2a5..500f2267921 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. +## 20.1.0 + +### General +- `IgxHierarchicalGrid` + - **Deprecation** - `schema` input property has been deprecated and will be removed in a future version. + ## 20.0.2 ### New Features diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts index fce5caf5528..258a01f67f3 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts @@ -27,7 +27,7 @@ import { QueryBuilderFunctions } from '../../query-builder/query-builder-functio import { By } from '@angular/platform-browser'; import { IgxDateTimeEditorDirective } from '../../directives/date-time-editor/date-time-editor.directive'; import { QueryBuilderSelectors } from '../../query-builder/query-builder.common'; -import { IgxHGridRemoteOnDemandComponent } from '../hierarchical-grid/hierarchical-grid.spec'; +import { IgxHGridRemoteOnDemandComponent, IgxHierarchicalGridToggleRIComponent } from '../hierarchical-grid/hierarchical-grid.spec'; import { IGridResourceStrings } from '../../core/i18n/grid-resources'; describe('IgxGrid - Advanced Filtering #grid - ', () => { @@ -1750,76 +1750,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(); - // 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'); + // 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(); + + // 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); + + // Verify return fields + QueryBuilderFunctions.clickQueryBuilderFieldsCombo(fixture, 1); + fixture.detectChanges(); + const innerQueryReturnFields = QueryBuilderFunctions.getQueryBuilderSelectDropdown(queryBuilderElement, 1); + + return innerQueryReturnFields; + }; - const fieldInputGroup = QueryBuilderFunctions.getQueryBuilderFieldsCombo(fixture, 1).querySelector('input'); - expect(fieldInputGroup.value).toBe('ID'); + 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/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts index 69695e21ee2..b44aff06c52 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts @@ -587,11 +587,10 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti * const schema = this.grid.schema; * this.grid.schema = [{ name: 'Products', fields: [...], childEntities: [...] }]; * ``` + * @deprecated in version 20.1.0. */ @Input() - public set schema(entities: EntityType[]) { - this._hGridSchema = entities; - } + public set schema(entities: EntityType[]) {} /* blazorSuppress */ public get schema() { @@ -683,6 +682,10 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti this.batchEditing = val; }); } + this.columnsAutogenerated.subscribe((e) => { + this.updateRootGridSchema(e); + }); + super.ngOnInit(); } @@ -1234,7 +1237,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) { @@ -1244,8 +1247,8 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti fields: filterableFields.map(f => ({ field: f.field, dataType: f.dataType, - // label: f.label, - // header: f.header, + label: f.label, + header: f.header, editorOptions: f.editorOptions, filters: f.filters, pipeArgs: f.pipeArgs, @@ -1256,7 +1259,7 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti ]; entities[0].childEntities = this.childLayoutList.reduce((acc, rowIsland) => { - return acc.concat(this.generateChildEntity(rowIsland, this.data[0][rowIsland.key][0])); + return acc.concat(this.generateChildEntity(rowIsland)); } , []); } @@ -1264,32 +1267,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; - } - return acc.concat(this.generateChildEntity(childRowIsland, firstRowData[childRowIsland.key][0])); + return acc.concat(this.generateChildEntity(childRowIsland)); }, []); if (rowIslandChildEntities?.length > 0) { diff --git a/projects/igniteui-angular/src/lib/query-builder/query-builder-tree.component.ts b/projects/igniteui-angular/src/lib/query-builder/query-builder-tree.component.ts index 7a59165e80c..36f23c9ce98 100644 --- a/projects/igniteui-angular/src/lib/query-builder/query-builder-tree.component.ts +++ b/projects/igniteui-angular/src/lib/query-builder/query-builder-tree.component.ts @@ -1410,7 +1410,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; } /**