Skip to content

fix(grid): fix zone.onStable patterns broken in zoneless change detection - 22.0.x#17453

Open
viktorkombov wants to merge 1 commit into
22.0.xfrom
vkombov/grid-zoneless-issues-22.0.x
Open

fix(grid): fix zone.onStable patterns broken in zoneless change detection - 22.0.x#17453
viktorkombov wants to merge 1 commit into
22.0.xfrom
vkombov/grid-zoneless-issues-22.0.x

Conversation

@viktorkombov

@viktorkombov viktorkombov commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

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-driven chunkLoad, column autosize, filter-row rendering, and post-scroll cell activation silently never ran.

This migrates all of that off onStable and onto Angular’s render hooks.

Changes

Core

  • Added a new central helper: runAfterRenderOnce(injector, cb, phase?) in core/utils.ts.

    • This is now the single scheduling point for all deferred-render work.
    • Previously, this logic was scattered across onStable / ɵNoopNgZone branches.
  • Updated every affected call site to go through runAfterRenderOnce.

  • Removed the private ɵNoopNgZone-based zoneless detection.

  • Removed the duplicated per-class runAfterRender helpers.

Grids

  • IgxFilteringService.isFilterRowVisible is now signal-backed, so the OnPush header row re-renders without requiring a zone tick.
  • Filter cells now observe their own size via ResizeObserver to recompute visible chips after resize.
  • Column resize now explicitly notifies the grid via notifyResized, instead of relying on an empty zone.run.
  • Keyboard navigation now notifies after any scrolling navigation key, not just Ctrl.
  • Hierarchical navigation now subscribes to chunkLoad before scrolling, avoiding missed synchronous emissions.
  • Deferred work in for_of, grid-base, and pivot-grid was migrated to runAfterRenderOnce.

Tests

  • Added zoneless duplicates using provideZonelessChangeDetection for the affected grid, tree, hierarchical, and pivot suites.

  • Centralized async test helpers in helper-utils.spec.ts.

  • runAfterRenderOnce consumers now settle through shared helpers:

    • waitForGridSettle
    • setGridVerticalScrollTop
    • dispatchGridScrollEvents
    • navigateWithGridScroll
  • Updated the zoned originals to await the new render-boundary timing.

    • Previously, they happened to align with onStable.

Notes

  • Behavior for zoned apps is unchanged in practice.

    • Real interaction still triggers a render.
    • Only the timing signal moved from onStable to afterNextRender.
  • No runOutsideAngular was removed.

  • No forced detectChanges was added in zoneless tests.

Motivation / Context

Type of Change (check all that apply):

  • Bug fix
  • New functionality
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactoring (no functional changes)
  • Documentation
  • Demos
  • CI/CD
  • Tests
  • Changelog
  • Skills/Agents

Component(s) / Area(s) Affected:

How Has This Been Tested?

  • Unit tests
  • Manual testing
  • Automated e2e tests

Test Configuration:

  • Angular version:
  • Browser(s):
  • OS:

Screenshots / Recordings

Checklist:

  • All relevant tags have been applied to this PR
  • This PR includes unit tests covering all the new code (test guidelines)
  • This PR includes API docs for newly added methods/properties (api docs guidelines)
  • This PR includes feature/README.MD updates for the feature docs
  • This PR includes general feature table updates in the root README.MD
  • This PR includes CHANGELOG.MD updates for newly added functionality
  • This PR contains breaking changes
  • This PR includes ng update migrations for the breaking changes (migrations guidelines)
  • This PR includes behavioral changes and the feature specification has been updated with them
  • Accessibility (ARIA, keyboard navigation, focus management) has been verified

Copilot AI review requested due to automatic review settings July 23, 2026 12:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 on afterNextRender) and uses it to replace zone.onStable deferrals in grids and IgxForOf.
  • 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() (or autoDetectChanges()) 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 cause getAdvancedFilteringComponent to 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();

@viktorkombov viktorkombov changed the title fix(grid): fix zone.onStable patterns broken in zoneless change detection fix(grid): fix zone.onStable patterns broken in zoneless change detection - 22.0.x Jul 23, 2026
@viktorkombov viktorkombov added the ❌ status: awaiting-test PRs awaiting manual verification label Jul 23, 2026
@mddragnev mddragnev added ✅ status: verified Applies to PRs that have passed manual verification and removed ❌ status: awaiting-test PRs awaiting manual verification labels Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants