When to use Ngzone.run()?
Asked Answered
C

3

61

I got a bug in my angular project which finally resolved by wrapping my code into

this.zone.run(() => {/* my code here */});

as stated by this answer.

My previous understanding of zone was that angular can't detect changes made by async callbacks of third-party libraries because "they are not in angular's zone". If I click on a button, the event that gets triggered is not browser's native click event but a custom (patched) click event created by angular whose handler runs in the zone so angular is aware of the changes made by its callback handler.

But I could not understand by running router.navigate() in third party callback create this problem (as indicated by this github issue). Isn't Router a service of angular itself? Why doesn't it automatically inform angular's zone when called in third party callback?

I got this problem by using router.navigate within state reducer of NGXS.

My question is:

Can someone explain when exactly do I need to wrap my code in NgZone?

Debugging for hours and realizing that my code is out of zone context is tiresome.

Celtic answered 21/7, 2018 at 11:22 Comment(4)
@dasfsa, if an event is not in "angular zone", angular can not detect the event. In others words, Angular can detect the router.navigate, but can not detect the event that make the router.navigate is executedAdapt
The example provided in doc does really explain its usage: angular.io/api/core/NgZone#example I was resolving some issue which directed me to this NgZone. My need was to update a property inside a component from a script outside in an iframe.Sclerophyll
And I put the demo here: stackblitz.com/edit/…Sclerophyll
I have found that I need this.ngZone.run(() => this.router.navigate(["login"])).then(); when navigating in an async function.Breaker
I
18

ngZone.runOutsideAngular() - this runs the code outside the angular zone.

  • When some event is fired it tells angular to detect changes.
  • If you are using mouseUp() or mouseDown() event, then on every change it tells angular to detect the changes.
  • If we don't want these changes to take place run-time in angular (which reduces performance of the app), we can run it outside of angular zone.
  • Contrast to this, if we keenly want to get each and every update then we can use ngZone.run(). Means it will run the change detection in normal.

Angular itself uses ngZone under the hood to detect the changes

So, if we have came out of angular zone, then to come back we use ngZone.run()

Inly answered 9/10, 2019 at 12:55 Comment(0)
N
9

ngZone.run() is particularly useful when unit testing your routing.

it('should redirect if condition true', fakeAsync(() => {
  router.navigate(['']);
  fixture.ngZone.run(() => {
    component.redirectIfConditionTrue();
  });
  tick();
  expect(location.path()).toBe('/AgentLeadsManager');
}));

source: its the only time i've ever had to use it

Nutting answered 18/10, 2019 at 15:51 Comment(0)
A
9

Zone.js is an execution context for tracking and intercepting async operations like: DOM events (click, keydown, keyup, etc), setTimeout, setInterval. XMLHttpRequests)

NgZone is just a wrapper angular service around Zone.js's API.

The Angular team decided they needed the abstraction for an execution context while working on Angular so they built Zone.js and a wrapper (informally - adapter pattern) around it in Angular.

So basically to answer your question: when dealing with any kind of 3rd party library which is not tied to Angular's run context within Zone.js (unless you decided you don't need execution context and you can work without it using NoopNgZone)

Source

Aphonia answered 18/10, 2019 at 17:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.