From 8d70419e2b00ce5d5964d8617a5fb1f4baa51507 Mon Sep 17 00:00:00 2001 From: Sebastian Niedworok Date: Tue, 2 Jun 2026 17:22:19 +0200 Subject: [PATCH] Clarify zoneless change detection --- 01-setup/README.md | 24 +------------------ 01-setup/src/app/app.config.ts | 13 ++-------- 02-first-graph/src/app/app.config.ts | 13 ++-------- 03-graph-builder/README.md | 21 +++++++++++++++- 03-graph-builder/src/app/app.config.ts | 13 ++-------- .../src/app/app.config.ts | 13 ++-------- 05-layout-worker/src/app/app.config.ts | 13 ++-------- 7 files changed, 31 insertions(+), 79 deletions(-) diff --git a/01-setup/README.md b/01-setup/README.md index 946f4b1..5ce2d1f 100644 --- a/01-setup/README.md +++ b/01-setup/README.md @@ -204,28 +204,7 @@ canvas based on the container dimensions, so an explicit size is required. --- -## 8. Zoneless change detection - -Angular's default change detection relies on Zone.js to intercept browser APIs. -Since yFiles fires its own events outside Angular's zone, it is cleaner to -opt in to **zoneless** change detection: - -```ts -// src/app/app.config.ts -import { provideZonelessChangeDetection } from '@angular/core' - -export const appConfig: ApplicationConfig = { - providers: [provideBrowserGlobalErrorListeners(), provideZonelessChangeDetection()], -} -``` - -With zoneless change detection, Angular only re-evaluates templates when a -signal value changes. This avoids spurious change-detection cycles triggered -by yFiles' internal DOM updates. - ---- - -## 9. Run it +## 8. Run it ```bash npm start @@ -247,7 +226,6 @@ Open `http://localhost:4200`. You should see a blank white canvas. Try panning | `@ViewChild` | Gives access to a template element reference by name. | | `ngAfterViewInit()` | Lifecycle hook that fires after the template is rendered. Use for DOM access. | | `GraphViewerInputMode` | Read-only interaction: pan, zoom, select. No graph editing. | -| `provideZonelessChangeDetection()` | Disables Zone.js; Angular only re-evaluates signals. Avoids spurious cycles from yFiles events. | --- diff --git a/01-setup/src/app/app.config.ts b/01-setup/src/app/app.config.ts index dfe8fa5..da9090d 100644 --- a/01-setup/src/app/app.config.ts +++ b/01-setup/src/app/app.config.ts @@ -1,14 +1,5 @@ -import { - type ApplicationConfig, - provideBrowserGlobalErrorListeners, - provideZonelessChangeDetection, -} from '@angular/core' +import { type ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core' export const appConfig: ApplicationConfig = { - providers: [ - // Angular 21 uses zoneless change detection by default. - // This is more efficient and works well with yFiles' imperative API. - provideBrowserGlobalErrorListeners(), - provideZonelessChangeDetection(), - ], + providers: [provideBrowserGlobalErrorListeners()], } diff --git a/02-first-graph/src/app/app.config.ts b/02-first-graph/src/app/app.config.ts index dfe8fa5..da9090d 100644 --- a/02-first-graph/src/app/app.config.ts +++ b/02-first-graph/src/app/app.config.ts @@ -1,14 +1,5 @@ -import { - type ApplicationConfig, - provideBrowserGlobalErrorListeners, - provideZonelessChangeDetection, -} from '@angular/core' +import { type ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core' export const appConfig: ApplicationConfig = { - providers: [ - // Angular 21 uses zoneless change detection by default. - // This is more efficient and works well with yFiles' imperative API. - provideBrowserGlobalErrorListeners(), - provideZonelessChangeDetection(), - ], + providers: [provideBrowserGlobalErrorListeners()], } diff --git a/03-graph-builder/README.md b/03-graph-builder/README.md index 766a99c..8d93d63 100644 --- a/03-graph-builder/README.md +++ b/03-graph-builder/README.md @@ -152,7 +152,7 @@ cause new elements to be created; missing IDs cause removal. ## 5. Angular signals — the reactive state layer This chapter introduces Angular's **signals API** as the reactive bridge -between application data and the graph. +between application data and the graph. See the Angular [Signals](https://angular.dev/guide/signals) documentation for in-depth explanations. ### `signal()` — mutable reactive state @@ -209,6 +209,25 @@ constructor( ) {} ``` +### Signals and zoneless change detection + +Angular 21 uses **zoneless** change detection by default. This means Angular no +longer relies on Zone.js — the library that traditionally monkey-patched browser +async APIs to trigger change detection after every Promise, `setTimeout`, or event. + +Signals are what make this possible. When a template reads a signal, Angular +registers an exact dependency. When that signal changes, only the affected views +are re-evaluated — Angular always knows precisely what changed. + +For a yFiles app this matters: yFiles' own render loop and internal event handlers +would otherwise trigger unnecessary change-detection passes under Zone.js. With +signals + zoneless, Angular and yFiles stay out of each other's way entirely. + +`app.config.ts` only needs `provideBrowserGlobalErrorListeners()` — no explicit +change-detection configuration is required. + +See the Angular [Zoneless](https://angular.dev/guide/zoneless) documentation for further information. + --- ## 6. `GraphViewComponent` — full implementation diff --git a/03-graph-builder/src/app/app.config.ts b/03-graph-builder/src/app/app.config.ts index dfe8fa5..da9090d 100644 --- a/03-graph-builder/src/app/app.config.ts +++ b/03-graph-builder/src/app/app.config.ts @@ -1,14 +1,5 @@ -import { - type ApplicationConfig, - provideBrowserGlobalErrorListeners, - provideZonelessChangeDetection, -} from '@angular/core' +import { type ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core' export const appConfig: ApplicationConfig = { - providers: [ - // Angular 21 uses zoneless change detection by default. - // This is more efficient and works well with yFiles' imperative API. - provideBrowserGlobalErrorListeners(), - provideZonelessChangeDetection(), - ], + providers: [provideBrowserGlobalErrorListeners()], } diff --git a/04-styles-and-interaction/src/app/app.config.ts b/04-styles-and-interaction/src/app/app.config.ts index dfe8fa5..da9090d 100644 --- a/04-styles-and-interaction/src/app/app.config.ts +++ b/04-styles-and-interaction/src/app/app.config.ts @@ -1,14 +1,5 @@ -import { - type ApplicationConfig, - provideBrowserGlobalErrorListeners, - provideZonelessChangeDetection, -} from '@angular/core' +import { type ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core' export const appConfig: ApplicationConfig = { - providers: [ - // Angular 21 uses zoneless change detection by default. - // This is more efficient and works well with yFiles' imperative API. - provideBrowserGlobalErrorListeners(), - provideZonelessChangeDetection(), - ], + providers: [provideBrowserGlobalErrorListeners()], } diff --git a/05-layout-worker/src/app/app.config.ts b/05-layout-worker/src/app/app.config.ts index dfe8fa5..da9090d 100644 --- a/05-layout-worker/src/app/app.config.ts +++ b/05-layout-worker/src/app/app.config.ts @@ -1,14 +1,5 @@ -import { - type ApplicationConfig, - provideBrowserGlobalErrorListeners, - provideZonelessChangeDetection, -} from '@angular/core' +import { type ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core' export const appConfig: ApplicationConfig = { - providers: [ - // Angular 21 uses zoneless change detection by default. - // This is more efficient and works well with yFiles' imperative API. - provideBrowserGlobalErrorListeners(), - provideZonelessChangeDetection(), - ], + providers: [provideBrowserGlobalErrorListeners()], }