Home Angular Tutorials Mastering Zone Hooks in Angular

Mastering Zone Hooks in Angular

by aouidane.med.amine
185,184 views 10 min read

This tutorial provides a comprehensive guide to understanding and working with Zone hooks in Angular.

Zone hooks are a powerful tool for customizing the behavior of asynchronous operations within an Angular application, and this tutorial will provide a deep dive into their usage.

By the end of the tutorial, you will have a comprehensive understanding of how to work with Zone hooks in Angular, and will be able to use them to optimize the performance and behavior of their Angular applications.

 

Table of Contents

What are Zone hooks & How do they work in Angular ?

Angular is using a JavaScript library named Zone.js to intercept and track all asynchronous operations and events that occur within a specific zone.

When any type of event occurs within a zone, Zone.js intercepts it and provides hooks for customizing its behavior through the use of “zone hooks”.

This allows us to control and customize the default behavior of asynchronous operations (track event progress, error handling … )

While the library is a pure JavaScript file, we cannot use it directly in our component; hence, angular has produced NgZone, a wrapper for the Zone.js library.

Zone hooks allow us to customize the behavior of asynchronous operations in the Angular application.

Angular has a wrapper class for Zone.js called NgZone

we can use it by injecting the ngZone service in the component (using the dependency injection system)

				
					 constructor(private zone: NgZone) { 
       this.zone.run(() => {
       // This is a new zone
       }
       );
     }
				
			

However, we are unable to use the full functionality of zone.js using this approach.

To do that, we need to use this method : 

				
					
public class appComponent {
  Zone: any;
  constructor() {
        Zone.current.fork({
            name: 'myCustomZone'
          }).run(() => {
            console.log('in myCustomzone? ', Zone.current.name);
          });
    }
}
				
			

Zone hooks in angular

Zone hooks are callback functions provided by the Zone.js library, which are used by Angular to intercept and track all asynchronous operations and events that occur within a specific zone.

Some of the most often used zone hooks are listed below :

onFork: Called when a new zone is created as a child of the current zone.

onIntercept: Called when an asynchronous operation or event is intercepted within the current zone.

onInvoke: Called when a function is invoked within the current zone.

onHandleError: Called when an error is thrown within the current zone.

By using these hooks, we can customize the default behavior of asynchronous operations within a specific zone, such as logging and error handling.

How to use onFork hook in angular ?

The onFork hook is a Zone.js callback function that is called when a new child zone is created from the current zone using the zone.fork() method.

This hook allows developers to customize the behavior of the child zone before it is created.

By default, Angular applications run within a single zone, but you can create and switch between zones using the Zone class provided by the library.

 

mastering zone hooks

The onFork hook requires two arguments: the zone that is now active (the “parent” zone) and the new child zone that is currently being generated.

The child zone’s data or state can be set up, and the child zone’s characteristics can be changed before it is created.

Here’s an example of how to use the onFork hook to modify the behavior of a child zone:

				
					public class appComponent {
Zone: any;

constructor() {
  
const parentZone = Zone.current;

const childZone = parentZone.fork({
  onFork: (parentZone, childZone) => {
    console.log('Child zone is being created');
    childZone.name = 'Custom Child Zone';
  }
});

console.log('Parent zone name:', parentZone.name);
console.log('Child zone name:', childZone.name);
  }
}
				
			

In this example, the onFork hook is used to set the name of the child zone to “Custom Child Zone” before it is created.

When the fork() method is called, the hook is executed, and the child zone is created with the custom name.

 

Why we Fork a zone ?

Forking a zone creates a new zone that inherits from the parent zone, but can also have its own settings and behavior. This is useful when we want to isolate specific parts of our application and apply different settings or behavior to them.

For Example, we might want to create a new zone with a different error handling strategy than the parent zone.
We can make sure that any errors that occur within the new zone are handled differently than errors that occur within the parent zone by forking the parent zone and configuring the new zone with a different error handling strategy.

Generally, forking a parent zone provides us more freedom and control over how our application behaves and performs. It also enables us to customize the behavior of various components of our application as necessary.

 

How to use onInvoke hook in angular ?

onInvoke is a callback method provided by the Zone.js library that is called when a function is invoked within the current zone.
This can be used to modify the behavior of functions, such as adding logging or error handling.

Here’s an example of using onInvoke to add error handling to a function:

In this example, we have an Angular component with a button that triggers a function when clicked.

The function may throw an error, so we want to add error handling to it.

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

@Component({
  selector: 'app-root',
  template: `
    <button (click)="onClick()">Click me</button>
  `
})
export class AppComponent {
  constructor(private ngZone: NgZone) {}

  onClick() {
    this.ngZone.run(() => {
      const someFunction = () => {
        // This function may throw an error
        throw new Error('Something went wrong!');
      };

      // Add error handling using the onInvoke hook
      const errorHandler = (parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs) => {
        try {
          return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs);
        } catch (error) {
          console.error(`Error occurred in ${delegate.name}: ${error.message}`);
          // Do something to handle the error, such as displaying an error message to the user
        }
      };

      // Wrap the original function with the error handler
      const wrappedFunction = Zone.current.fork({
        name: 'Error handling zone',
        onInvoke: errorHandler
      }).wrap(someFunction);

      wrappedFunction();
    });
  }
}

				
			

As you see, we are using the method ngZone.run() to run and execute the function in the current zone.
In this zone, we define ‘errorHandler‘ callback function to the onInvoke hook
that wraps the original function with error handling logic.

The errorHandler function takes the same arguments as the onInvoke hook and delegates the function call to the parent zone using parentZoneDelegate.invoke().

If an error occurs, the function catches the error, logs a message to the console, and performs some other error handling logic.

We then create a new zone using Zone.current.fork() and provide the onInvoke callback function as an option.

We wrap the original function with the error handler using the wrap() method and call the resulting wrapped function.

How to use onIntercept hook in angular ?

The onIntercept hook in Angular is another type of Zone.js hook that you can use to modify the behavior of functions within a specific zone.

It allows you to intercept function calls before they are executed and potentially modify the arguments or return value.

Here is a brief explanation of the onIntercept hook:

  • 'onIntercept' is called when a function is intercepted (before it is executed) within the current zone.
  • The hook is passed a delegate, which is the function that is about to be executed, as well as the arguments that were passed to the function.
  • The hook can modify the arguments or return value of the function by returning a new array of arguments or a new value, respectively.

Here’s an example of how to use the onIntercept zone hook in Angular :

Suppose you want to intercept and modify all HTTP requests made within your Angular application. You can do this by creating a new zone and defining an onIntercept hook for that zone.

Here’s how you can create a new zone and define the onIntercept hook

				
					import { NgZone } from '@angular/core';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class HttpInterceptorService {
  Zone: any;
  constructor() {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const zone = Zone.current.fork({
      name: 'httpInterceptorZone',
      onIntercept: (parentZoneDelegate, currentZone, targetZone, delegate, source) => {
        return parentZoneDelegate.intercept(source, next).pipe(
          tap((event) => {
            // modify the response
            console.log(`Response received: ${event}`);
          })
        );
      },
    });
    return zone.run(() => next.handle(req));
  }
}

				
			

In this example, the intercept() method is called whenever an HTTP request is made within your Angular application. It creates a new zone called httpInterceptorZone and defines an onIntercept hook for that zone.

The onIntercept hook is called whenever an asynchronous operation is intercepted within the httpInterceptorZone. It receives several parameters, including the parentZoneDelegate, currentZone, targetZone, delegate, and source

In this example, the onIntercept hook uses the parentZoneDelegate to intercept the HTTP request and modify the response. It then logs the modified response to the console.

Finally, the intercept() method returns the result of running the HTTP request within the httpInterceptorZone using the zone.run() method.

By using the onIntercept hook in this way, you can customize the behavior of HTTP requests within your Angular application, such as modifying the response or adding custom error handling.

How to use onHandleError hook in angular ?

The onHandleError hook in Angular is a type of Zone.js hook that you can use to intercept errors that occur within a specific zone.

It allows you to provide custom error handling logic, such as logging the error or displaying a user-friendly error message.

Here is a brief explanation of the onHandleError hook:

  • When an error happens within the current zone, onHandleError callback is invoked.
  • The error object and a callback function that can be used to manage the error are supplied to the hook.

Here’s an example of using the onHandleError hook to log errors in an Angular application:

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

@Component({
  selector: 'app-root',
  template: `
    <button (click)="onClick()">Click me</button>
  `
})
export class AppComponent {
  constructor(private ngZone: NgZone) {
    // Add a custom error handler using the onHandleError hook
    ngZone.onHandleError = (error) => {
      console.error('Error occurred:', error);
      // Return true to prevent the error from being re-thrown
      return true;
    };
  }

  onClick() {
    this.ngZone.run(() => {
      // Throw an error within the zone
      throw new Error('Some error occurred');
    });
  }
}

				
			

In this example, we have an Angular component with a button that triggers an error when clicked.

The error is thrown within a zone using the ngZone.run() method.

In the constructor of the component, we override the onHandleError method of the ngZone object with a custom error handling function.

This function logs the error to the console and returns true to prevent the error from being thrown again.

In this example, we’re just logging the error to the console. However, you could provide more advanced error handling logic in the onHandleError hook, such as displaying a user-friendly error message or sending the error to a logging service.

onInvoke VS onIntercept

The main difference between the onInvoke and onIntercept hooks in Zone.js is that
OnInvoke is called after a function has been called within the current zone (after the function has been called), whereas onIntercept is called before the function is called (when the function is about to be called).

Here’s a summary of the key differences:

  • onInvoke is called after a function is invoked, while onIntercept is called before a function is invoked
  • onInvoke receives the actual return value of the function as an argument, while onIntercept does not receive the return value
  • onInvoke cannot prevent a function from executing, while onIntercept can return a special flag, ZoneSymbol.INTERCEPTED, to prevent a function from executing.
  • onInvoke is more useful for adding behavior to a function after it has been called, such as logging or error handling
  • onIntercept is more suited for modifying the default behavior of a function before it is called, such as modifying its arguments or return value

References and Links

You may also like