-
Notifications
You must be signed in to change notification settings - Fork 160
fix(hgrid): add and use lifecycle placeholder for grid connection eve… #17242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 21.2.x
Are you sure you want to change the base?
Changes from all commits
122d801
ad14b90
6281d2b
7baf0e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1065,7 +1065,7 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U | |
| this.scrollFocus(embView.rootNodes.find(node => node.nodeType === Node.ELEMENT_NODE) | ||
| || embView.rootNodes[0].nextElementSibling); | ||
| const view = container.detach(0); | ||
|
|
||
| view.detectChanges(); | ||
| this.updateTemplateContext(embView.context, i); | ||
| container.insert(view); | ||
| this._embeddedViews.push(embView); | ||
|
|
@@ -1085,7 +1085,7 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U | |
| this.scrollFocus(embView.rootNodes.find(node => node.nodeType === Node.ELEMENT_NODE) | ||
| || embView.rootNodes[0].nextElementSibling); | ||
| const view = container.detach(container.length - 1); | ||
|
|
||
| view.detectChanges(); | ||
| this.updateTemplateContext(embView.context, i); | ||
| container.insert(view, 0); | ||
|
Comment on lines
1087
to
1090
|
||
| this._embeddedViews.unshift(embView); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -36,6 +36,7 @@ import { IgxIconComponent } from 'igniteui-angular/icon'; | |||||||||||||||
| import { EntityType, FieldType, IFilteringExpressionsTree, IgxActionStripToken, IgxOverlayOutletDirective, flatten, IGridResourceStrings } from 'igniteui-angular/core'; | ||||||||||||||||
| import { IgxPaginatorToken } from 'igniteui-angular/paginator'; | ||||||||||||||||
| import { IgxGridCellMergePipe, IgxGridComponent, IgxGridFilteringPipe, IgxGridSortingPipe, IgxGridUnmergeActivePipe } from 'igniteui-angular/grids/grid'; | ||||||||||||||||
| import { registerLifecyclePlaceholderElement } from './lifecycle-placeholder-element'; | ||||||||||||||||
|
|
||||||||||||||||
| let NEXT_ID = 0; | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -662,6 +663,9 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti | |||||||||||||||
| * @hidden | ||||||||||||||||
| */ | ||||||||||||||||
| public override ngOnInit() { | ||||||||||||||||
| if (this.platform.isBrowser) { | ||||||||||||||||
| registerLifecyclePlaceholderElement(); | ||||||||||||||||
| } | ||||||||||||||||
| // this.expansionStatesChange.pipe(takeUntil(this.destroy$)).subscribe((value: Map<any, boolean>) => { | ||||||||||||||||
| // const res = Array.from(value.entries()).filter(({1: v}) => v === true).map(([k]) => k); | ||||||||||||||||
| // }); | ||||||||||||||||
|
|
@@ -674,6 +678,26 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti | |||||||||||||||
| super.ngOnInit(); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Event that triggers when element gets connected back to the DOM. | ||||||||||||||||
| // Used to determine when to reopen a previously closed row editing overlay. | ||||||||||||||||
| protected onLifecyclePlaceholderConnected(): void { | ||||||||||||||||
| if (this.rowEditable && this.crudService.rowInEditMode && this.rowEditingOverlay && | ||||||||||||||||
| this.rowEditingOverlay.collapsed) { | ||||||||||||||||
| // Row is in edit mode, but overlay is closed - reopen. | ||||||||||||||||
| this.openRowOverlay(this.crudService.rowInEditMode.id); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Event that triggers when element gets disconnected from the DOM, for example as a result of virtualization or caching. | ||||||||||||||||
| // Used to determine when to close the row editing overlay. | ||||||||||||||||
| protected onLifecyclePlaceholderDisconnected(): void { | ||||||||||||||||
| if (this.rowEditable && this.crudService.rowInEditMode && this.rowEditingOverlay) { | ||||||||||||||||
| // disconnected from DOM (possibly cached) & row was in edit mode - close overlay. | ||||||||||||||||
|
Comment on lines
+695
to
+696
|
||||||||||||||||
| if (this.rowEditable && this.crudService.rowInEditMode && this.rowEditingOverlay) { | |
| // disconnected from DOM (possibly cached) & row was in edit mode - close overlay. | |
| const overlay = this.rowEditingOverlay; | |
| if (this.rowEditable && this.crudService.rowInEditMode && overlay && | |
| !overlay.collapsed && overlay.element?.parentElement) { | |
| // disconnected from DOM (possibly cached) & row was in edit mode - close overlay | |
| // only if it is still open and attached. |
Copilot
AI
Apr 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New connect/disconnect-driven behavior for row edit overlay state (close on disconnect, reopen on reconnect) is added here, but there are existing hgrid specs (including virtualization ones) and none appear to cover this scenario. Please add a regression test that starts row edit in a child grid, virtualizes/detaches it (scroll/collapse), and verifies the overlay is restored when reconnected.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| const LIFECYCLE_PLACEHOLDER_TAG = 'igc-lifecycle-placeholder'; | ||
| const LIFECYCLE_CONNECTED_EVENT = 'igcConnected'; | ||
| const LIFECYCLE_DISCONNECTED_EVENT = 'igcDisconnected'; | ||
|
|
||
| /** @hidden @internal */ | ||
| export function registerLifecyclePlaceholderElement(): void { | ||
| if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined' || | ||
| typeof CustomEvent === 'undefined' || customElements.get(LIFECYCLE_PLACEHOLDER_TAG)) { | ||
| return; | ||
| } | ||
|
|
||
| class LifecyclePlaceholderElement extends HTMLElement { | ||
| public connectedCallback(): void { | ||
| this.dispatchEvent(new CustomEvent(LIFECYCLE_CONNECTED_EVENT)); | ||
| } | ||
|
|
||
| public disconnectedCallback(): void { | ||
| this.dispatchEvent(new CustomEvent(LIFECYCLE_DISCONNECTED_EVENT)); | ||
| } | ||
| } | ||
|
|
||
| customElements.define(LIFECYCLE_PLACEHOLDER_TAG, LifecyclePlaceholderElement); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -146,12 +146,12 @@ <h4 class="sample-title">Sample two</h4> | |
| <igx-grid-toolbar-exporter></igx-grid-toolbar-exporter> | ||
| </igx-grid-toolbar-actions> | ||
| </igx-grid-toolbar> | ||
| <igx-row-island [key]="'childData'" [autoGenerate]="true" [rowSelection]='selectionMode' [batchEditing]="true" [rowEditable]="true" | ||
| <igx-row-island [rowEditable]="true" [primaryKey]="'ID'" [key]="'childData'" [autoGenerate]="true" [rowSelection]='selectionMode' [batchEditing]="true" [rowEditable]="true" | ||
| [allowFiltering]="true"> | ||
| <igx-row-island [key]="'childData'" [autoGenerate]="true" [rowSelection]='selectionMode' [batchEditing]="true" [rowEditable]="true" | ||
| <igx-row-island [rowEditable]="true" [primaryKey]="'ID'" [key]="'childData'" [autoGenerate]="true" [rowSelection]='selectionMode' [batchEditing]="true" [rowEditable]="true" | ||
| [allowFiltering]="true"></igx-row-island> | ||
|
Comment on lines
+149
to
152
|
||
| </igx-row-island> | ||
| <igx-row-island [key]="'childData2'" [autoGenerate]="true" [allowFiltering]="true"></igx-row-island> | ||
| <igx-row-island [rowEditable]="true" [primaryKey]="'ID'" [key]="'childData2'" [autoGenerate]="true" [allowFiltering]="true"></igx-row-island> | ||
| </igx-hierarchical-grid> | ||
|
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
view.detectChanges()is called beforeupdateTemplateContext(embView.context, i), so the view will run change detection with the old context. If the goal is to refresh the recycled view immediately (and/or flush DOM connect/disconnect), update the context first and then calldetectChanges()(or batch the detection outside the loop).