DEV Community

Soumaya Erradi
Soumaya Erradi

Posted on

9 1 1 1 1

Angular Change Detection with Zoneless

Change detection is at the heart of every Angular application. It ensures that the application's user interface (UI) stays in sync with its data model. Traditionally, Angular has relied on a mechanism called zones, powered by the zone.js library, to make this happen. But with Angular’s latest version, a new zoneless change detection feature is introduced, marking a significant shift in how developers can optimize their applications.

In this article, we will explore:

  1. How change detection works in Angular.
  2. Problems caused by zones.
  3. The introduction of zoneless mode and how to use it.
  4. Handling complex situations with zoneless change detection.
  5. Why signals and zoneless mode are a powerful combination.
  6. The benefits and revolutionary impact of this feature.

Understanding Change Detection in Angular

Change detection is the process Angular uses to make sure the application's UI is always updated with the latest data. This happens automatically whenever something changes in your application, whether it’s a user action, an HTTP request or a timer event.

In Angular, every component has its own change detection mechanism, which checks if the values in the component's template have changed and updates the DOM accordingly.

Zones and their role

Angular has traditionally used zone.js to patch asynchronous operations such as:

  • HTTP requests.
  • Event listeners (e.g., button clicks).
  • Timers like setTimeout or setInterval.

When any of these operations are completed, zone.js automatically triggers Angular's change detection mechanism, ensuring the UI stays in sync. This makes development easier, as developers don’t need to worry about manually updating the UI.


The problems with Zones

While zone.js simplifies development, it introduces some challenges:

  1. Performance overhead: By patching all asynchronous operations, zone.js adds unnecessary overhead, especially in large or high-performance applications.
  2. Debugging complexity: Debugging issues becomes harder because zone.js modifies how asynchronous operations work under the hood.
  3. Compatibility issues: Some modern browser APIs and third-party libraries don’t work well with zone.js.
  4. Unnecessary change detection: Angular’s change detection runs even when the application’s state hasn’t changed, leading to wasted resources.

The Zoneless revolution in Angular

With the release of Angular v19, the framework introduced an experimental zoneless mode to address these problems. Zoneless mode allows Angular to run without zone.js, giving developers more control over when and how change detection happens.

What does Zoneless mode do?

In zoneless mode:

  • Angular no longer automatically tracks asynchronous operations.
  • Developers must manually trigger change detection when data changes.
  • The application becomes leaner and faster since there’s no overhead from zone.js.

How to use Zoneless mode

Zoneless mode might feel like a significant shift, but breaking it into clear steps ensures a smooth transition. Here's a detailed guide:

Step 1: Disable Zone.js

To disable zones, start by removing the zone.js library from your application.

  1. Update polyfills.ts: Remove or comment out the import for zone.js:
   // polyfills.ts
   // Remove or comment out the following line:
   // import 'zone.js';
Enter fullscreen mode Exit fullscreen mode
  1. Remove from Dependencies: Check your package.json and remove zone.js from the dependencies section:
   {
     "dependencies": {
       "zone.js": "^0.12.0" // Remove this dependency
     }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Uninstall the Library: Run the following command to uninstall zone.js completely:
   npm uninstall zone.js
Enter fullscreen mode Exit fullscreen mode

Step 2: Bootstrap without Zone.js

Angular provides a dedicated function, provideExperimentalZonelessChangeDetection(), to enable zoneless mode in your application. This function ensures that Angular initializes without zone.js and uses the experimental zoneless change detection.

Here’s how to configure it in your main.ts file:

import { bootstrapApplication } from '@angular/platform-browser';
import { provideExperimentalZonelessChangeDetection } from '@angular/core';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideExperimentalZonelessChangeDetection(), // Enable zoneless change detection
  ],
}).catch(err => console.error(err));
Enter fullscreen mode Exit fullscreen mode

Step 3: Manually trigger change detection

Once zones are disabled, Angular will no longer automatically run change detection. You need to trigger it manually when state changes occur.

Using ChangeDetectorRef

The ChangeDetectorRef service allows you to invoke change detection at the component level. Additionally, the markForCheck() method is useful in scenarios where you want Angular to schedule change detection for components with OnPush change detection strategy:

import { Component, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div>
      <h1>Counter: {{ counter }}</h1>
      <button (click)="incrementCounter()">Increment</button>
    </div>
  `,
})
export class AppComponent {
  counter = 0;

  constructor(private cdr: ChangeDetectorRef) {}

  incrementCounter() {
    this.counter++;
    this.cdr.markForCheck(); // Mark the component for checking during the next change detection cycle
  }
}
Enter fullscreen mode Exit fullscreen mode

Using ApplicationRef

For global state changes, you can use ApplicationRef.tick() to trigger change detection across the entire application:

import { Component, ApplicationRef } from '@angular/core';

@Component({
  selector: 'app-global-tick',
  template: `
    <button (click)="updateState()">Update State</button>
    <p>{{ message }}</p>
  `,
})
export class GlobalTickComponent {
  message = 'Initial State';

  constructor(private appRef: ApplicationRef) {}

  updateState() {
    this.message = 'Updated State';
    this.appRef.tick(); // Trigger change detection globally
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Optimize with Signals

Angular signals, introduced with Angular's new reactivity model, are an excellent companion to zoneless mode. Signals track state changes efficiently and automatically update the UI without manual calls to change detection.

Here’s a simple example using signals:

import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-signal-demo',
  template: `
    <h1>Signal Counter: {{ count() }}</h1>
    <button (click)="increment()">Increment</button>
  `,
})
export class SignalDemoComponent {
  count = signal(0);

  increment() {
    this.count.set(this.count() + 1);
  }
}
Enter fullscreen mode Exit fullscreen mode

In this setup, the signal automatically tracks changes, and the UI updates without the need for explicit detectChanges calls.


Handling complex situations

Scenario: multiple data streams

When working with multiple asynchronous streams (e.g., using RxJS), AsyncPipe remains a reliable solution in zoneless mode. It simplifies data binding and eliminates the need for manual change detection:

import { Component } from '@angular/core';
import { interval } from 'rxjs';

@Component({
  selector: 'app-multi-stream',
  template: `<p>Stream Value: {{ value$ | async }}</p>`
})
export class MultiStreamComponent {
  value$ = interval(1000); // Emits a value every second
}
Enter fullscreen mode Exit fullscreen mode

Why Zoneless mode is revolutionary

  1. Performance gains: Applications become faster and more efficient by eliminating zone-related overhead.
  2. Developer control: Zoneless mode lets you decide when to update the UI, leading to better-optimized apps.
  3. Compatibility: Works seamlessly with modern APIs and third-party libraries.
  4. Enhanced reactivity: Combined with signals, zoneless mode simplifies state management and improves app responsiveness.

Conclusion

The introduction of zoneless change detection in Angular is a game-changer. It empowers developers to build faster, more efficient applications while giving them greater control over how and when updates happen. Coupled with Angular signals, zoneless mode unlocks new possibilities for optimizing performance and simplifying state management.

As Angular continues to evolve, features like this reinforce its position as one of the most versatile and powerful frameworks for modern web development!

Heroku

Deploy with ease. Manage efficiently. Scale faster.

Leave the infrastructure headaches to us, while you focus on pushing boundaries, realizing your vision, and making a lasting impression on your users.

Get Started

Top comments (4)

Collapse
 
melroy89 profile image
Melroy van den Berg • Edited

I used to use a @Input() user!: SomeUserObject in my edit form. Which gets set when the HttpClient retrieved the data.
And in my HTML template I was using:

@if (user) {
}
Enter fullscreen mode Exit fullscreen mode

For example. This now no longer works we I try to go zoneless, so what is the best way forward. What are the best practices to migrate? I'm not sure I need to use signal here..

Collapse
 
soumayaerradi profile image
Soumaya Erradi

Great question!
In zoneless mode, Angular no longer runs change detection automatically when the @Input() is set by an async operation (like your HttpClient call). That's why your @if (user) doesn't react anymore.

You have a couple of options:

  • Use ChangeDetectorRef.markForCheck() right after setting the input.
  • If your input is set asynchronously, wrapping it in a signal can help re-trigger change detection automatically.
  • You can switch to using an Observable + AsyncPipe, which still works well with zoneless.
Collapse
 
melroy89 profile image
Melroy van den Berg

Thanks! I now also have something similar with @Output when using reusable shared components..
I guess from all your options, signal is the future. And the preferred way. What do you think?

Collapse
 
fabiobiondi profile image
Fabio Biondi

Useful tips 👏
Thank you for sharing.

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →