fix(grid): fix zone.onStable patterns broken in zoneless change detection - 22.0.x#17453
Open
viktorkombov wants to merge 1 commit into
Open
fix(grid): fix zone.onStable patterns broken in zoneless change detection - 22.0.x#17453viktorkombov wants to merge 1 commit into
viktorkombov wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates grid/virtualization and autosizing scheduling to work correctly under Angular zoneless change detection, replacing NgZone.onStable-based deferrals (which don’t emit without Zone.js) with an afterNextRender-based helper. It also adds/adjusts regression tests to validate keyboard navigation, virtualization, and autosizing behavior in zoneless mode.
Changes:
- Introduces
runAfterRenderOnce()(based onafterNextRender) and uses it to replacezone.onStabledeferrals in grids andIgxForOf. - Updates grid keyboard navigation logic to notify the grid when virtualization scroll occurs, even without
ctrl, ensuring activation/selection stays correct. - Expands/adjusts unit tests to cover zoneless change detection scenarios and to reduce timing-based flakiness.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| projects/igniteui-angular/test-utils/tree-grid-components.spec.ts | Adds a helper Tree Grid test component with many columns to force horizontal virtualization scenarios. |
| projects/igniteui-angular/grids/tree-grid/src/tree-grid.component.spec.ts | Reworks an auto-generation test to use async stability patterns instead of fakeAsync/tick. |
| projects/igniteui-angular/grids/tree-grid/src/tree-grid-summaries.spec.ts | Replaces timing waits with whenStable() and enables auto-detection in a scrolling regression test. |
| projects/igniteui-angular/grids/tree-grid/src/tree-grid-keyBoardNav.spec.ts | Adds a zoneless keyboard navigation regression test for virtualized target activation. |
| projects/igniteui-angular/grids/tree-grid/src/tree-grid-integration.spec.ts | Adds a zoneless autosize alignment regression test plus a supporting component. |
| projects/igniteui-angular/grids/pivot-grid/src/pivot-grid.component.ts | Replaces zone.onStable(first()) autosize deferral with runAfterRenderOnce(). |
| projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-grid.virtualization.spec.ts | Enables fixture auto change detection in a virtualization regression test. |
| projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-grid.navigation.spec.ts | Adds zoneless change detection coverage and stabilizes navigation tests with explicit chunk-load waits. |
| projects/igniteui-angular/grids/grid/src/grid.search.spec.ts | Enables fixture auto change detection in a search + scroll regression test. |
| projects/igniteui-angular/grids/grid/src/grid.master-detail.spec.ts | Adds zoneless master-detail keyboard navigation regression tests. |
| projects/igniteui-angular/grids/grid/src/grid.groupby.spec.ts | Adds zoneless grouped virtualization regression test for horizontal state restoration. |
| projects/igniteui-angular/grids/grid/src/grid.component.spec.ts | Adds zoneless rendering regression tests for vertical/horizontal virtualization and ARIA stability. |
| projects/igniteui-angular/grids/grid/src/grid-mrl-keyboard-nav.spec.ts | Enables fixture auto change detection in MRL keyboard navigation tests. |
| projects/igniteui-angular/grids/grid/src/grid-keyBoardNav.spec.ts | Enables fixture auto change detection for a high-virtualization keyboard navigation test. |
| projects/igniteui-angular/grids/grid/src/grid-keyBoardNav-headers.spec.ts | Converts one test to async/zoned-stability patterns (currently missing needed detectChanges() calls). |
| projects/igniteui-angular/grids/grid/src/grid-filtering-ui.spec.ts | Switches filter-chip interactions to a UI-based helper and adjusts a resize interaction coordinate. |
| projects/igniteui-angular/grids/grid/src/grid-cell-selection.spec.ts | Adds zoneless keyboard selection regression coverage and stabilizes async sequencing. |
| projects/igniteui-angular/grids/grid/src/grid-base.directive.ts | Replaces multiple zone.onStable scheduling points with runAfterRenderOnce() for autosize/virtualization/width updates. |
| projects/igniteui-angular/grids/grid/src/column.spec.ts | Adds zoneless autosizing regression test for fit-content widths after data changes. |
| projects/igniteui-angular/grids/grid/src/column-group.spec.ts | Makes width assertions more tolerant (within 1px) and shifts to async timing stabilization. |
| projects/igniteui-angular/grids/core/src/grid-navigation.service.ts | Expands virtualization-notification logic to cover scroll-causing nav keys beyond ctrl+up/down. |
| projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts | Replaces afterNextRender/zone.onStable patterns with runAfterRenderOnce() and fixes a reduce() edge case. |
| projects/igniteui-angular/core/src/core/utils.ts | Introduces runAfterRenderOnce() helper and a render-phase type to centralize deferred render scheduling. |
Comments suppressed due to low confidence (3)
projects/igniteui-angular/grids/grid/src/grid-keyBoardNav-headers.spec.ts:487
- After simulating the header click, the fixture needs
detectChanges()(orautoDetectChanges()) so the focus/selection changes are reflected before continuing the assertions/keyboard interactions.
let header = GridFunctions.getColumnHeader('Name', fix);
UIInteractions.simulateClickAndSelectEvent(header);
await fix.whenStable();
projects/igniteui-angular/grids/grid/src/grid-keyBoardNav-headers.spec.ts:493
- Opening Advanced Filtering via keyboard should run change detection after the key event; awaiting
whenStable()alone will not update the DOM, which can causegetAdvancedFilteringComponentto return null intermittently.
UIInteractions.triggerEventHandlerKeyDown('L', gridHeader, true);
await fix.whenStable();
projects/igniteui-angular/grids/grid/src/grid-keyBoardNav-headers.spec.ts:501
- After sending Escape and waiting, call
detectChanges()so the dialog close and focus restoration are reflected in the fixture before assertions.
UIInteractions.triggerKeyDownEvtUponElem('Escape', afDialog);
await wait(100);
await fix.whenStable();
ChronosSF
approved these changes
Jul 23, 2026
rkaraivanov
approved these changes
Jul 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #17364
Closes #17385
Closes #17318
Closes #17280
What
Grid virtualization, autosizing, and keyboard navigation relied on
NgZone.onStable, which never emits in zoneless apps. As a result, scroll-drivenchunkLoad, column autosize, filter-row rendering, and post-scroll cell activation silently never ran.This migrates all of that off
onStableand onto Angular’s render hooks.Changes
Core
Added a new central helper:
runAfterRenderOnce(injector, cb, phase?)incore/utils.ts.onStable/ɵNoopNgZonebranches.Updated every affected call site to go through
runAfterRenderOnce.Removed the private
ɵNoopNgZone-based zoneless detection.Removed the duplicated per-class
runAfterRenderhelpers.Grids
IgxFilteringService.isFilterRowVisibleis now signal-backed, so theOnPushheader row re-renders without requiring a zone tick.ResizeObserverto recompute visible chips after resize.notifyResized, instead of relying on an emptyzone.run.Ctrl.chunkLoadbefore scrolling, avoiding missed synchronous emissions.for_of,grid-base, andpivot-gridwas migrated torunAfterRenderOnce.Tests
Added zoneless duplicates using
provideZonelessChangeDetectionfor the affected grid, tree, hierarchical, and pivot suites.Centralized async test helpers in
helper-utils.spec.ts.runAfterRenderOnceconsumers now settle through shared helpers:waitForGridSettlesetGridVerticalScrollTopdispatchGridScrollEventsnavigateWithGridScrollUpdated the zoned originals to await the new render-boundary timing.
onStable.Notes
Behavior for zoned apps is unchanged in practice.
onStabletoafterNextRender.No
runOutsideAngularwas removed.No forced
detectChangeswas added in zoneless tests.Motivation / Context
Type of Change (check all that apply):
Component(s) / Area(s) Affected:
How Has This Been Tested?
Test Configuration:
Screenshots / Recordings
Checklist:
feature/README.MDupdates for the feature docsREADME.MDCHANGELOG.MDupdates for newly added functionalityng updatemigrations for the breaking changes (migrations guidelines)