fix(grid): fix zone.onStable patterns broken in zoneless change detection - 21.2.x#17387
Open
viktorkombov wants to merge 1 commit into
Open
fix(grid): fix zone.onStable patterns broken in zoneless change detection - 21.2.x#17387viktorkombov 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 fixes multiple Grid (and related) features that previously relied on NgZone.onStable—which does not emit under Angular’s zoneless change detection—by migrating deferred DOM-/render-dependent work to Angular render hooks and aligning tests with the new render-boundary timing.
Changes:
- Added
runAfterRenderOnce(injector, cb, phase?)and migratedonStable-scheduled work across grids, virtualization, and related infrastructure to render hooks. - Updated Grid internals for zoneless correctness (e.g., virtualization scroll pipelines, autosizing, resizing notifications, keyboard navigation scheduling).
- Added/updated zoneless test coverage using
provideZonelessChangeDetection()plus shared async helpers for scroll/navigation settling.
Reviewed changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| projects/igniteui-angular/core/src/core/utils.ts | Adds central runAfterRenderOnce helper built on afterNextRender. |
| projects/igniteui-angular/grids/grid/src/grid-base.directive.ts | Replaces zone.onStable scheduling with runAfterRenderOnce and adjusts navigation callback guards. |
| projects/igniteui-angular/grids/pivot-grid/src/pivot-grid.component.ts | Migrates dimension autosize scheduling off onStable onto render hooks. |
| projects/igniteui-angular/grids/core/src/resizing/resizing.service.ts | Ensures column resize notifies the grid in zoneless via render-bound callback. |
| projects/igniteui-angular/grids/core/src/grid-navigation.service.ts | Broadens virtualized keyboard-selection notifications to any key that scrolls. |
| projects/igniteui-angular/grids/core/src/filtering/grid-filtering.service.ts | Makes isFilterRowVisible signal-backed to re-render OnPush views in zoneless. |
| projects/igniteui-angular/grids/core/src/filtering/base/grid-filtering-cell.component.ts | Adds resize observation so filter-chip visibility recalculates under zoneless. |
| projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.ts | Migrates virtualization post-scroll work to render hooks; fixes reduce-on-empty edge case. |
| projects/igniteui-angular/test-utils/helper-utils.spec.ts | Adds shared async/settling helpers for scroll/navigation and zoneless scroll detection. |
| projects/igniteui-angular/directives/src/directives/for-of/for_of.directive.spec.ts | Adds zoneless coverage for virtualization size recalculation after scroll. |
| projects/igniteui-angular/grids/grid/src/grid.search.spec.ts | Updates timing around grouping + scroll highlight navigation; adds zoneless duplicate. |
| projects/igniteui-angular/grids/grid/src/grid.master-detail.spec.ts | Updates navigation timing and adds zoneless navigation coverage for master-detail scenarios. |
| projects/igniteui-angular/grids/grid/src/grid.groupby.spec.ts | Adds zoneless regression for horizontal virtualization state restore with cached row views. |
| projects/igniteui-angular/grids/grid/src/grid.component.spec.ts | Replaces fixed delays with settle helpers; adds zoneless ARIA attribute regression. |
| projects/igniteui-angular/grids/grid/src/grid-mrl-keyboard-nav.spec.ts | Replaces fixed delays with navigation+scroll settling helpers; adds zoneless coverage. |
| projects/igniteui-angular/grids/grid/src/grid-keyBoardNav.spec.ts | Documents/adjusts zoned timing; adds zoneless virtualized navigation coverage. |
| projects/igniteui-angular/grids/grid/src/grid-keyBoardNav-headers.spec.ts | Updates header navigation timing to await render-hook-driven state restoration; adds zoneless coverage. |
| projects/igniteui-angular/grids/grid/src/grid-filtering-ui.spec.ts | Adds zoneless filtering-row UI coverage and adjusts resize-driven indicator assertions. |
| projects/igniteui-angular/grids/grid/src/grid-cell-selection.spec.ts | Replaces fixed delays with settle helper; adds zoneless selection regression. |
| projects/igniteui-angular/grids/grid/src/column.spec.ts | Adds zoneless coverage for date/time editor formatting behaviors. |
| projects/igniteui-angular/grids/grid/src/column-group.spec.ts | Stabilizes width assertions (pixel tolerance) and adds zoneless duplicate coverage. |
| projects/igniteui-angular/grids/tree-grid/src/tree-grid.component.spec.ts | Updates auto-generate timing and adds zoneless auto-generate coverage. |
| projects/igniteui-angular/grids/tree-grid/src/tree-grid-summaries.spec.ts | Adds zoneless runtime summary settings coverage and stabilizes async waits. |
| projects/igniteui-angular/grids/tree-grid/src/tree-grid-keyBoardNav.spec.ts | Stabilizes scroll-driven keyboard navigation via shared scroll helpers; adds zoneless suite. |
| projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-grid.virtualization.spec.ts | Uses shared scroll-top helper; adds zoneless virtualization regressions and increases timeout budget. |
| projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-grid.navigation.spec.ts | Stabilizes scroll/navigation timing and adds zoneless navigation coverage with init/scroll settling helpers. |
| projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-grid-navigation.service.ts | Subscribes to chunkLoad before scrolling to avoid missed synchronous emissions. |
| projects/igniteui-angular/grids/pivot-grid/src/pivot-grid-keyboard-nav.spec.ts | Uses settle helper for horizontal virtualization navigation instead of fixed delays. |
| projects/igniteui-angular/query-builder/src/query-builder/query-builder.component.spec.ts | Replaces generated expression tree with explicit FilteringExpressionsTree initialization. |
| projects/igniteui-angular-elements/src/app/custom-strategy.spec.ts | Replaces timer-based waits with childrenResolved event synchronization. |
| import { TestBed, waitForAsync } from '@angular/core/testing'; | ||
| import { NoopAnimationsModule } from '@angular/platform-browser/animations'; | ||
| import { Component, ViewChild } from '@angular/core'; | ||
| import { Component, ViewChild, ChangeDetectionStrategy, provideZonelessChangeDetection } from '@angular/core'; |
| import { TestBed, waitForAsync } from '@angular/core/testing'; | ||
| import { NoopAnimationsModule } from '@angular/platform-browser/animations'; | ||
| import { Component, ViewChild, DebugElement} from '@angular/core'; | ||
| import { Component, ViewChild, DebugElement, ChangeDetectionStrategy, provideZonelessChangeDetection } from '@angular/core'; |
| @@ -1,15 +1,16 @@ | |||
| import { Component, ViewChild, OnInit, DebugElement, QueryList, TemplateRef, ViewChildren } from '@angular/core'; | |||
| import { Component, ViewChild, OnInit, DebugElement, QueryList, TemplateRef, ViewChildren, ChangeDetectionStrategy, provideZonelessChangeDetection } from '@angular/core'; | |||
| @@ -1,4 +1,4 @@ | |||
| import { Component, ViewChild, TemplateRef, QueryList } from '@angular/core'; | |||
| import { Component, ViewChild, TemplateRef, QueryList, ChangeDetectionStrategy, provideZonelessChangeDetection } from '@angular/core'; | |||
| @@ -1,4 +1,4 @@ | |||
| import { AfterViewInit, ChangeDetectorRef, Component, Injectable, OnInit, ViewChild, TemplateRef, inject } from '@angular/core'; | |||
| import { AfterViewInit, ChangeDetectorRef, Component, Injectable, OnInit, ViewChild, TemplateRef, inject, ChangeDetectionStrategy, provideZonelessChangeDetection } from '@angular/core'; | |||
| @@ -1,4 +1,4 @@ | |||
| import { Component, DebugElement, TemplateRef, ViewChild } from '@angular/core'; | |||
| import { Component, DebugElement, TemplateRef, ViewChild, ChangeDetectionStrategy, provideZonelessChangeDetection } from '@angular/core'; | |||
| @@ -1,5 +1,5 @@ | |||
| import { AsyncPipe, NgClass, NgForOfContext } from '@angular/common'; | |||
| import { AfterViewInit, ChangeDetectorRef, Component, Directive, Injectable, IterableDiffers, NgZone, OnInit, QueryList, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, DebugElement, Pipe, PipeTransform, inject } from '@angular/core'; | |||
| import { AfterViewInit, ChangeDetectorRef, Component, Directive, Injectable, IterableDiffers, NgZone, OnInit, QueryList, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, DebugElement, Pipe, PipeTransform, inject, ChangeDetectionStrategy, provideZonelessChangeDetection } from '@angular/core'; | |||
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)