From d38f068780ae81aef58043391de10718cb623e4d Mon Sep 17 00:00:00 2001 From: Viktor Kombov Date: Wed, 2 Apr 2025 21:30:23 +0300 Subject: [PATCH 1/3] feat(hierarchical-grid): add parentRowData to IGridCreatedEventArgs --- .../src/lib/grids/hierarchical-grid/events.ts | 1 + .../hierarchical-grid.component.ts | 9 +++-- .../hierarchical-grid.pipes.ts | 2 +- .../hierarchical-grid.spec.ts | 39 +++++++++++++++++-- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/events.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/events.ts index 437b47ccb74..fea356e7817 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/events.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/events.ts @@ -7,4 +7,5 @@ export interface IGridCreatedEventArgs extends IBaseEventArgs { owner: IgxRowIslandComponent; parentID: any; grid: IgxHierarchicalGridComponent; + parentRowData?: any; } 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 a06f2a229f7..61698be51cc 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 @@ -196,8 +196,9 @@ export class IgxChildGridRowComponent implements AfterViewInit, OnInit { */ public ngOnInit() { const ref = this.container.createComponent(IgxHierarchicalGridComponent, { injector: this.container.injector }); + const childGridData = this.data.childGridsData[this.layout.key]; this.hGrid = ref.instance; - this.hGrid.setDataInternal(this.data.childGridsData[this.layout.key]); + this.hGrid.setDataInternal(childGridData); this.hGrid.nativeElement["__componentRef"] = ref; this.layout.layoutChange.subscribe((ch) => { this._handleLayoutChanges(ch); @@ -214,7 +215,8 @@ export class IgxChildGridRowComponent implements AfterViewInit, OnInit { this.layout.gridCreated.emit({ owner: this.layout, parentID: this.data.rowID, - grid: this.hGrid + grid: this.hGrid, + parentRowData: !childGridData?.length ? this.data.parentRowData : undefined, }); } @@ -231,7 +233,8 @@ export class IgxChildGridRowComponent implements AfterViewInit, OnInit { this.layout.gridInitialized.emit({ owner: this.layout, parentID: this.data.rowID, - grid: this.hGrid + grid: this.hGrid, + parentRowData: !this.hGrid.data.length ? this.data.parentRowData : undefined, }); this.hGrid.cdr.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.pipes.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.pipes.ts index a5ed11596d8..46636a25880 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.pipes.ts @@ -49,7 +49,7 @@ export class IgxGridHierarchicalPipe implements PipeTransform { childGridsData[childKey] = childData; }); if (grid.gridAPI.get_row_expansion_state(v)) { - result.push({ rowID: primaryKey ? v[primaryKey] : v, childGridsData }); + result.push({ rowID: primaryKey ? v[primaryKey] : v, childGridsData, parentRowData: v }); } }); return result; diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts index ca4d8382731..fd2102c0cf0 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts @@ -686,12 +686,14 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { fixture.detectChanges(); const childGrids = hierarchicalGrid.gridAPI.getChildGrids(false); const childRows = fixture.debugElement.queryAll(By.directive(IgxChildGridRowComponent)); - expect(childGrids.length).toBe(2); - expect(childRows.length).toBe(2); + expect(childGrids.length).toBe(3); + expect(childRows.length).toBe(3); const ri1 = fixture.componentInstance.rowIsland1; const ri2 = fixture.componentInstance.rowIsland2; + const ri3 = fixture.componentInstance.rowIsland3; expect(childRows[0].componentInstance.layout).toBe(ri1); expect(childRows[1].componentInstance.layout).toBe(ri2); + expect(childRows[2].componentInstance.layout).toBe(ri3); }); it('should display correct data for sibling row islands', () => { @@ -865,11 +867,13 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { fixture.detectChanges(); const children = hierarchicalGrid.gridAPI.getChildGrids(true); - expect(children.length).toBe(2); + expect(children.length).toBe(3); const child1 = children[0] as IgxHierarchicalGridComponent; const child2 = children[1] as IgxHierarchicalGridComponent; + const child3 = children[2] as IgxHierarchicalGridComponent; expect(child1._destroyed).toBeFalsy(); expect(child2._destroyed).toBeFalsy(); + expect(child3._destroyed).toBeFalsy(); hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(); fixture.detectChanges(); @@ -877,6 +881,7 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { // check that we have child is not destroyed expect(child1._destroyed).toBeFalsy(); expect(child2._destroyed).toBeFalsy(); + expect(child3._destroyed).toBeFalsy(); // destroy hgrid fixture.destroy(); @@ -1119,6 +1124,32 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { expect(getterSpy).toHaveBeenCalledTimes(7); expect(summaryCell.textContent.trim()).toEqual(''); })); + + it('should verify gridCreated and gridInitialized events emit correct parentRowData for grids with and without data.', () => { + const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent; + const ri1 = fixture.componentInstance.rowIsland1; + const ri3 = fixture.componentInstance.rowIsland3; + + spyOn(ri1.gridCreated, 'emit').and.callThrough(); + spyOn(ri1.gridInitialized, 'emit').and.callThrough(); + spyOn(ri3.gridCreated, 'emit').and.callThrough(); + spyOn(ri3.gridInitialized, 'emit').and.callThrough(); + + UIInteractions.simulateClickAndSelectEvent(row.expander); + fixture.detectChanges(); + + // Verify parentRowData is undefined for grids with existing data + expect(ri1.gridCreated.emit).toHaveBeenCalledTimes(1); + expect(ri1.gridCreated.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: undefined })); + expect(ri1.gridInitialized.emit).toHaveBeenCalledTimes(1); + expect(ri1.gridInitialized.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: undefined })); + + // Verify parentRowData is defined for grids without data + expect(ri3.gridCreated.emit).toHaveBeenCalledTimes(1); + expect(ri3.gridCreated.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: row.data })); + expect(ri3.gridInitialized.emit).toHaveBeenCalledTimes(1); + expect(ri3.gridInitialized.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: row.data })); + }); }); describe('IgxHierarchicalGrid Children Sizing #hGrid', () => { @@ -1984,12 +2015,14 @@ export class IgxHierarchicalGridTestBaseComponent { + `, imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent] }) export class IgxHierarchicalGridMultiLayoutComponent extends IgxHierarchicalGridTestBaseComponent { @ViewChild('rowIsland1', { read: IgxRowIslandComponent, static: true }) public rowIsland1: IgxRowIslandComponent; @ViewChild('rowIsland2', { read: IgxRowIslandComponent, static: true }) public override rowIsland2: IgxRowIslandComponent; + @ViewChild('rowIsland3', { read: IgxRowIslandComponent, static: true }) public rowIsland3: IgxRowIslandComponent; public height = '100px'; public toggleColumns = true; } From ed210338a14168a76b16a32438553462ae510136 Mon Sep 17 00:00:00 2001 From: Viktor Kombov Date: Fri, 4 Apr 2025 10:22:12 +0300 Subject: [PATCH 2/3] chore(*): Always include parentRowData in the arguments --- .../hierarchical-grid.component.ts | 4 +- .../hierarchical-grid.spec.ts | 39 ++++++------------- 2 files changed, 13 insertions(+), 30 deletions(-) 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 61698be51cc..e204ba8f75c 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 @@ -216,7 +216,7 @@ export class IgxChildGridRowComponent implements AfterViewInit, OnInit { owner: this.layout, parentID: this.data.rowID, grid: this.hGrid, - parentRowData: !childGridData?.length ? this.data.parentRowData : undefined, + parentRowData: this.data.parentRowData, }); } @@ -234,7 +234,7 @@ export class IgxChildGridRowComponent implements AfterViewInit, OnInit { owner: this.layout, parentID: this.data.rowID, grid: this.hGrid, - parentRowData: !this.hGrid.data.length ? this.data.parentRowData : undefined, + parentRowData: this.data.parentRowData, }); this.hGrid.cdr.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts index fd2102c0cf0..7960c35a376 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts @@ -686,14 +686,12 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { fixture.detectChanges(); const childGrids = hierarchicalGrid.gridAPI.getChildGrids(false); const childRows = fixture.debugElement.queryAll(By.directive(IgxChildGridRowComponent)); - expect(childGrids.length).toBe(3); - expect(childRows.length).toBe(3); + expect(childGrids.length).toBe(2); + expect(childRows.length).toBe(2); const ri1 = fixture.componentInstance.rowIsland1; const ri2 = fixture.componentInstance.rowIsland2; - const ri3 = fixture.componentInstance.rowIsland3; expect(childRows[0].componentInstance.layout).toBe(ri1); expect(childRows[1].componentInstance.layout).toBe(ri2); - expect(childRows[2].componentInstance.layout).toBe(ri3); }); it('should display correct data for sibling row islands', () => { @@ -867,13 +865,11 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { fixture.detectChanges(); const children = hierarchicalGrid.gridAPI.getChildGrids(true); - expect(children.length).toBe(3); + expect(children.length).toBe(2); const child1 = children[0] as IgxHierarchicalGridComponent; const child2 = children[1] as IgxHierarchicalGridComponent; - const child3 = children[2] as IgxHierarchicalGridComponent; expect(child1._destroyed).toBeFalsy(); expect(child2._destroyed).toBeFalsy(); - expect(child3._destroyed).toBeFalsy(); hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(); fixture.detectChanges(); @@ -881,7 +877,6 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { // check that we have child is not destroyed expect(child1._destroyed).toBeFalsy(); expect(child2._destroyed).toBeFalsy(); - expect(child3._destroyed).toBeFalsy(); // destroy hgrid fixture.destroy(); @@ -1125,30 +1120,20 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { expect(summaryCell.textContent.trim()).toEqual(''); })); - it('should verify gridCreated and gridInitialized events emit correct parentRowData for grids with and without data.', () => { + it('should verify gridCreated and gridInitialized events emit correct parentRowData', () => { const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent; - const ri1 = fixture.componentInstance.rowIsland1; - const ri3 = fixture.componentInstance.rowIsland3; + const rowIsland = fixture.componentInstance.rowIsland1; - spyOn(ri1.gridCreated, 'emit').and.callThrough(); - spyOn(ri1.gridInitialized, 'emit').and.callThrough(); - spyOn(ri3.gridCreated, 'emit').and.callThrough(); - spyOn(ri3.gridInitialized, 'emit').and.callThrough(); + spyOn(rowIsland.gridCreated, 'emit').and.callThrough(); + spyOn(rowIsland.gridInitialized, 'emit').and.callThrough(); UIInteractions.simulateClickAndSelectEvent(row.expander); fixture.detectChanges(); - // Verify parentRowData is undefined for grids with existing data - expect(ri1.gridCreated.emit).toHaveBeenCalledTimes(1); - expect(ri1.gridCreated.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: undefined })); - expect(ri1.gridInitialized.emit).toHaveBeenCalledTimes(1); - expect(ri1.gridInitialized.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: undefined })); - - // Verify parentRowData is defined for grids without data - expect(ri3.gridCreated.emit).toHaveBeenCalledTimes(1); - expect(ri3.gridCreated.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: row.data })); - expect(ri3.gridInitialized.emit).toHaveBeenCalledTimes(1); - expect(ri3.gridInitialized.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: row.data })); + expect(rowIsland.gridCreated.emit).toHaveBeenCalledTimes(1); + expect(rowIsland.gridCreated.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: row.data })); + expect(rowIsland.gridInitialized.emit).toHaveBeenCalledTimes(1); + expect(rowIsland.gridInitialized.emit).toHaveBeenCalledWith(jasmine.objectContaining({ parentRowData: row.data })); }); }); @@ -2015,14 +2000,12 @@ export class IgxHierarchicalGridTestBaseComponent { - `, imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent] }) export class IgxHierarchicalGridMultiLayoutComponent extends IgxHierarchicalGridTestBaseComponent { @ViewChild('rowIsland1', { read: IgxRowIslandComponent, static: true }) public rowIsland1: IgxRowIslandComponent; @ViewChild('rowIsland2', { read: IgxRowIslandComponent, static: true }) public override rowIsland2: IgxRowIslandComponent; - @ViewChild('rowIsland3', { read: IgxRowIslandComponent, static: true }) public rowIsland3: IgxRowIslandComponent; public height = '100px'; public toggleColumns = true; } From 785b4e2a3380952919eec917afd066eda53ede2e Mon Sep 17 00:00:00 2001 From: Viktor Kombov Date: Fri, 4 Apr 2025 10:33:41 +0300 Subject: [PATCH 3/3] chore(*): clean up leftover --- .../lib/grids/hierarchical-grid/hierarchical-grid.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 e204ba8f75c..4b06865bfdf 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 @@ -196,9 +196,8 @@ export class IgxChildGridRowComponent implements AfterViewInit, OnInit { */ public ngOnInit() { const ref = this.container.createComponent(IgxHierarchicalGridComponent, { injector: this.container.injector }); - const childGridData = this.data.childGridsData[this.layout.key]; this.hGrid = ref.instance; - this.hGrid.setDataInternal(childGridData); + this.hGrid.setDataInternal(this.data.childGridsData[this.layout.key]); this.hGrid.nativeElement["__componentRef"] = ref; this.layout.layoutChange.subscribe((ch) => { this._handleLayoutChanges(ch);