DEV Community

Cover image for Deactivate Angular NgZone selectively — the easy way
Daniel Glejzner for This is Angular

Posted on • Updated on • Originally published at Medium

Deactivate Angular NgZone selectively — the easy way

Generated by MidJourney AI

A fine-grained control over Angular's change detection mechanism is here and ready to be used!

Signals and change detection optimization is not quite there yet. But even today there are ways to help you manage change detection easily.

The reactive extensions for Angular, RxAngular, provide us with powerful tools to control and optimize our application performance. One of these tools is the unpatch directive.

Generated by MidJourney AI

What is Unpatch Directive?

In Angular, the NgZone service manages the execution of tasks inside or outside Angular’s change detection mechanism. Veteran Angular developers describe this as two zones. By default, Angular runs almost everything inside an Angular Zone, meaning any asynchronous operations like setTimeout, Promise, or any DOM events will trigger Angular's change detection.

While this default mechanism ensures that the UI is consistently updated with the latest changes, it can lead to performance issues when handling high-frequency events, such as mousemove or scroll. These events can trigger a large number of unnecessary change detection cycles.

This is where the unpatch directive steps in. By using unpatch, we can prevent certain events from triggering change detection — improving performance. The directive can be used on any element to which you apply event bindings.

    <button unpatch (click)="triggerSomeMethod($event)">click me</button>
Enter fullscreen mode Exit fullscreen mode

The unpatch directive prevents the 'click' event from triggering Angular's change detection. By default unpatch all registered listeners of the host it is applied on. If you want you to specify exactly what to unpatch - you can provide a list as shown in examples below.

Generated by MidJourney AI

How to utilize unpatch in your app

Let’s dive into a real-world scenario where unpatch can significantly boost performance. Imagine we're building a real-time data visualization tool, handling a large number of DOM elements and several high-frequency events like mousemove, scroll, etc.

Initially, we have a component rendering a large dataset in a tabular format. Each row of the table has a hover effect showing additional data.

    <div *ngFor="let data of largeDataSet">
      <div (mousemove)="showAdditionalData(data)" class="data-row">
        <!-- Basic data display -->
      </div>
    </div>
Enter fullscreen mode Exit fullscreen mode

In this scenario, the mousemove event fires very frequently, triggering change detection for the entire component tree. Even if the additional data doesn’t change, Angular still rerenders the component tree, leading to performance issues.

Now, let’s optimize this with the unpatch directive:

    <div *ngFor="let data of largeDataSet">
      <div [unpatch]="['mousemove']" (mousemove)="showAdditionalData(data)" class="data-row">
        <!-- Basic data display -->
      </div>
    </div>
Enter fullscreen mode Exit fullscreen mode

By using unpatch, we're instructing Angular not to run change detection every time the 'mousemove' event fires.

Generated by MidJourney AI

Kanban Board

Imagine a Kanban board application where users can drag and drop tasks between different columns.

    <div class="task" 
         (dragstart)="dragStart($event, task)" 
         (dragover)="dragOver($event)" 
         (drop)="drop($event, column)">
      <!-- Task display -->
    </div>
Enter fullscreen mode Exit fullscreen mode

Here, the dragstart, dragover, and drop events are firing when a user drags a task and drops it onto another column. Each of these events triggers Angular’s change detection, which can lead to performance issues, especially with a large number of tasks.

Now, let’s optimize this with the unpatch directive:

    <div class="task" 
         [unpatch]="['dragstart', 'dragover', 'drop']" 
         (dragstart)="dragStart($event, task)" 
         (dragover)="dragOver($event)" 
         (drop)="drop($event, column)">
      <!-- Task display -->
    </div>
Enter fullscreen mode Exit fullscreen mode

With the unpatch directive, the dragstart, dragover, and drop events will no longer trigger Angular's change detection. As a result, the performance of the application can significantly improve when users are frequently dragging and dropping tasks.

However, please note that you would need to manually trigger change detection if any of these events cause changes that should be reflected in the UI!

Angular’s ChangeDetectorRef service allows you to manually run change detection on a component and its child components. You can use its detectChanges method to manually trigger change detection:

    constructor(private changeDetector: ChangeDetectorRef) {}

    drop(event: DragEvent, column: Column) {
      // logic 

      // manually trigger change detection
      this.changeDetector.detectChanges();
    }
Enter fullscreen mode Exit fullscreen mode

The unpatch directive provided by the RxAngular library is a powerful tool for optimizing Angular applications. By preventing unnecessary change detection cycles, it helps to improve the performance and responsiveness of applications.

Make sure to also check out other goodies that RxAngular offers.


I hope you liked my article!

If you did you might also like what I am doing on Twitter. I am hosting live Twitter Spaces about Angular with GDEs & industry experts! You can participate live, ask your questions or watch replays in a form of short clips :)

If you are interested drop me a follow on Twitter @DanielGlejzner — would mean a lot :). Thank You!

Top comments (2)

Collapse
 
spock123 profile image
Lars Rye Jeppesen

Great stuff

Collapse
 
rebaiahmed profile image
Ahmed Rebai

Could your prove for us the usage of this directive with real application and see the performance results before and after?