Skip to main content

Posts

Showing posts with the label Angular

Angular Zoneless Architecture: Handling 'ExpressionChangedAfterItHasBeenChecked' with Signals

  Removing   zone.js   reduces bundle size and improves stack trace clarity, but it does not remove the fundamental laws of Angular's Unidirectional Data Flow. In fact, relying purely on Signals can expose race conditions in your reactive graph that Zone.js previously masked (or managed differently). One specific edge case in enterprise applications involves "Layout Thrashing" scenarios: a child component renders, calculates a dimension based on its content, and attempts to update a shared Signal that drives the parent's layout. In a Zoneless environment, doing this naïvely within an  effect  triggers  ExpressionChangedAfterItHasBeenCheckedError  (NG0100) or, worse, an infinite change detection loop. The Root Cause: Signal Graph Instability In the Zone.js era, this error occurred because a lifecycle hook (like  ngAfterViewInit ) updated a property that had already been bound to the DOM in the parent view. Angular had finished checking the parent, ...

Debugging Angular Zoneless Change Detection: When Signals Don't Update the View

  You have enabled   provideZonelessChangeDetection()   in your   app.config.ts . You have modernized your components to use Signals. Yet, there are pockets of your application—specifically inside   setTimeout ,   setInterval , or third-party library callbacks—where state changes are ignored by the render cycle. The data model updates, but the DOM remains stale until you click a button or resize the window. This is not a bug in Angular 18+. It is a rigorous enforcement of reactivity that Zone.js previously allowed you to ignore. The Root Cause: Zone.js Masked Mutation Bugs To understand the fix, you must understand what you removed. Zone.js  worked by monkey-patching browser APIs ( Promise ,  setTimeout ,  addEventListener ). Whenever any async macro-task completed, Zone.js assumed something  might  have changed and triggered a top-down check ( ApplicationRef.tick() ). This architecture had a side effect:  It hid reactivity vio...