diff --git a/projects/igniteui-angular-elements/src/app/custom-strategy.spec.ts b/projects/igniteui-angular-elements/src/app/custom-strategy.spec.ts index 1b5b3795f02..6f22a889abf 100644 --- a/projects/igniteui-angular-elements/src/app/custom-strategy.spec.ts +++ b/projects/igniteui-angular-elements/src/app/custom-strategy.spec.ts @@ -12,6 +12,8 @@ import { IgcPaginatorComponent, IgcGridStateComponent, IgcColumnLayoutComponent, + IgcActionStripComponent, + IgcGridEditingActionsComponent, } from './components'; import { defineComponents } from '../utils/register'; @@ -27,6 +29,8 @@ describe('Elements: ', () => { IgcColumnLayoutComponent, IgcPaginatorComponent, IgcGridStateComponent, + IgcActionStripComponent, + IgcGridEditingActionsComponent ); }); @@ -230,5 +234,66 @@ describe('Elements: ', () => { expect(grid.columns.length).toEqual(6); expect(grid.getColumnByVisibleIndex(1).field).toEqual('ProductName'); }); + + it('should not destroy action strip when row it is shown in is destroyed or cached.', async() => { + const innerHtml = ` + + + + + `; + testContainer.innerHTML = innerHtml; + + // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy + await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3)); + + const grid = document.querySelector>('#testGrid'); + const actionStrip = document.querySelector>('#testStrip'); + grid.data = SampleTestData.foodProductData(); + + // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy + await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3)); + + let row = grid.dataRowList.toArray()[0]; + actionStrip.show(row); + await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3)); + + expect(actionStrip.hidden).toBeFalse(); + + grid.data = []; + await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3)); + + // row destroyed + expect((row.cdr as any).destroyed).toBeTrue(); + // action strip still in DOM, only hidden. + expect(actionStrip.hidden).toBeTrue(); + expect(actionStrip.isConnected).toBeTrue(); + + grid.data = SampleTestData.foodProductData(); + grid.groupBy({ fieldName: 'InStock', dir: 1, ignoreCase: false }); + + // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy + await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3)); + + row = grid.dataRowList.toArray()[0]; + actionStrip.show(row); + await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3)); + + expect(actionStrip.hidden).toBeFalse(); + + // collapse all data rows, leave only groups + grid.toggleAllGroupRows(); + + // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy + await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 3)); + + // row not destroyed, but also not in dom anymore + expect((row.cdr as any).destroyed).toBeFalse(); + expect(row.element.nativeElement.isConnected).toBe(false); + + // action strip still in DOM, only hidden. + expect(actionStrip.hidden).toBeTrue(); + expect(actionStrip.isConnected).toBeTrue(); + }); }); }); diff --git a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.spec.ts b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.spec.ts index 4a86a58fdf4..34750256cd2 100644 --- a/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.spec.ts +++ b/projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-editing-actions.component.spec.ts @@ -15,6 +15,7 @@ import { IgxGridPinningActionsComponent } from './grid-pinning-actions.component import { IgxActionStripComponent } from '../action-strip.component'; import { IRowDataCancelableEventArgs, IgxColumnComponent } from '../../grids/public_api'; import { SampleTestData } from '../../test-utils/sample-test-data.spec'; +import { SortingDirection } from '../../data-operations/sorting-strategy'; describe('igxGridEditingActions #grid ', () => { let fixture; @@ -274,6 +275,59 @@ describe('igxGridEditingActions #grid ', () => { expect(actionStrip.hidden).toBeTrue(); }); + + it('should auto-hide on delete action click.', () => { + const row = grid.rowList.toArray()[0]; + actionStrip.show(row); + fixture.detectChanges(); + + expect(actionStrip.hidden).toBeFalse(); + + const deleteIcon = fixture.debugElement.queryAll(By.css(`igx-grid-editing-actions igx-icon`))[1]; + expect(deleteIcon.nativeElement.innerText).toBe('delete'); + deleteIcon.parent.triggerEventHandler('click', new Event('click')); + fixture.detectChanges(); + + expect(actionStrip.hidden).toBeTrue(); + + }); + + it('should auto-hide if context row is destroyed.', () => { + const row = grid.rowList.toArray()[0]; + actionStrip.show(row); + fixture.detectChanges(); + + expect(actionStrip.hidden).toBeFalse(); + + // bind to no data, which removes all rows. + grid.data = []; + grid.cdr.detectChanges(); + + expect((row.cdr as any).destroyed).toBeTrue(); + expect(actionStrip.hidden).toBeTrue(); + }); + + it('should auto-hide if context row is cached.', () => { + // create group rows + grid.groupBy({ fieldName: 'ContactTitle', dir: SortingDirection.Desc, ignoreCase: false }); + fixture.detectChanges(); + + // show for first data row + const row = grid.dataRowList.toArray()[0]; + actionStrip.show(row); + fixture.detectChanges(); + + // collapse all groups to cache data rows + grid.toggleAllGroupRows(); + fixture.detectChanges(); + + // not destroyed, but not in DOM anymore + expect((row.cdr as any).destroyed).toBeFalse(); + expect(row.element.nativeElement.isConnected).toBe(false); + + // action strip should be hidden + expect(actionStrip.hidden).toBeTrue(); + }); }); describe('auto show/hide in HierarchicalGrid', () => { diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index fdd88ba2794..43e842cf87a 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -6438,6 +6438,12 @@ export abstract class IgxGridBaseDirective implements GridType, } } + protected viewDetachHandler(args) { + if (this.actionStrip && args.view.rootNodes.find(x => x === this.actionStrip.context?.element.nativeElement)) { + this.actionStrip.hide(); + } + } + /** * @hidden @internal */ diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html index 9631c1bd71a..95887b56f24 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.html @@ -107,6 +107,7 @@ [igxTemplateOutletContext]="getContext(rowData, rowIndex)" (cachedViewLoaded)="cachedViewLoaded($event)" (viewCreated)="viewCreatedHandler($event)" + (beforeViewDetach)="viewDetachHandler($event)" (viewMoved)="viewMovedHandler($event)"> diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html index 276e89cb377..95659846e36 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html @@ -83,7 +83,7 @@ + (viewMoved)="viewMovedHandler($event)" (cachedViewLoaded)="cachedViewLoaded($event)" (beforeViewDetach)="viewDetachHandler($event)"> diff --git a/projects/igniteui-angular/src/lib/grids/row.directive.ts b/projects/igniteui-angular/src/lib/grids/row.directive.ts index 81a0bced344..4752e1ce936 100644 --- a/projects/igniteui-angular/src/lib/grids/row.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/row.directive.ts @@ -492,6 +492,10 @@ export class IgxRowDirective implements DoCheck, AfterViewInit, OnDestroy { * @internal */ public ngOnDestroy() { + // if action strip is shown here but row is about to be destroyed, hide it. + if (this.grid.actionStrip && this.grid.actionStrip.context === this) { + this.grid.actionStrip.hide(); + } this.destroy$.next(true); this.destroy$.complete(); } diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html index 33c79416332..e43960b4bbb 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.html @@ -88,6 +88,7 @@ (dataChanging)="dataRebinding($event)" (dataChanged)="dataRebound($event)">