Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?

AngularAngular RouterZonejs

Angular Problem Overview


I am using Angular 7 and facing an issue => after login the API GET calls successfully and the component receiving data too, but UI is not displaying that data.

When I open the browser console, immediately the data gets populated on the UI and a warning is showing in the console. > "core.js:15686 Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?"

I have googled this warning and found some workaround like this.ngZone.run() and call my API's inside it.

But the issue is, I am using more than 40 components and calling so many API in each component. So I have to call ngZone.run() on each API call, which seems to be difficult to do.

Please suggest me the better approach to overcome this issue. Thanks in advance.

> app.component.ts

getEmployees(): void {
    this.employeeService.getEmployees().subscribe(e => {
        this.employees = e;
    });
}

> app.service.ts

@Injectable()
export class EmployeeService {
    constructor(private httpClient: HttpClient) { }

    getEmployees() {
        return this.httpClient.get<EmployeeModel[]>('employees');
    }

Angular Solutions


Solution 1 - Angular

Usually this happens when you are wrapping angular calls inside some external js callback, from external JavaScript not related to angular code.

Example app.component.ts:

callMyCustomJsLibrary() {
  googleSdk.getLocations(location => this.getEmployees());
}

getEmployees(): void {
    this.employeeService.getEmployees().subscribe(e => {
        this.employees = e;
    });
}

In this case you will have to include the call into the NgZone, example: this.ngZone.run(() => this.getEmployees());

The app.component.ts would then look like the following:

callMyCustomJsLibrary() {
  googleSdk.getLocations(location => this.ngZone.run(() => this.getEmployees()));
}

getEmployees(): void {
    this.employeeService.getEmployees().subscribe(e => {
        this.employees = e;
    });
}

Solution 2 - Angular

My issue fixed by wrapping the router navigation command in ngZone. Please check the code below

in constructor add "private zone: NgZone".

private zone: NgZone

this.zone.run(() => {
                    this.router.navigate(['/login']);
                });

Solution 3 - Angular

If I talk from top then the meaning of this warning is that the event is triggered outside of zone. Angular uses zones, also called execution contexts for change detection and UI rendering. So while navigating, Angular expects to re-renderer the UI but it is not happening here. That's the problem you are facing. So it throws this warning because Angular is processing the change detection and UI rendering when the code executed lies inside of Angular zone.

But actually, this warning comes when you are trying to call the router navigation inside the subscribe method.

If you put your router navigation call outside of subscribe method then it will not throw this warning again and you will see the expected UI after navigation.

For more information about zones, read and watch the videos mentioned below:

https://blog.thoughtram.io/angular/2017/02/21/using-zones-in-angular-for-better-performance.html#running-outside-angulars-zone

https://www.youtube.com/watch?v=3IqtmUscE_U&t=150

Solution 4 - Angular

I had the same problem. This worked for me, you have two ways:

First form:

document.location.href=`/component/${param}/...`

The problem with this is that it will reload the entire application and this will make it slower

Second method:

Import this

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

constructor:

 constructor(private _ngZone: NgZone, private _router: Router) { }


  goTo(comp, param){
    this._ngZone.run(()=>{
    this._router.navigate([comp, param])
    });
  }

So when you want to go to your component, simply:

this.goTo("/myComponent", "my-param-value");

I hope it works for you

Solution 5 - Angular

Working Solution - FIX

 ngAfterViewInit(): void {
    let self = this;
      this.platform.backButton.subscribe(() => {
      console.log("back preseed \n \n");

      self._ngZone.runOutsideAngular(() => {
        setTimeout(() => {
          self.Router.navigateByUrl("/stock-management");
        }, 100);
      });
    });
  }

Solution 6 - Angular

This happens if you try injecting a custom made service:

constructor(private myService: MyService) {
}

while you forgot to provide it in the module configuration:

@NgModule({
  providers: [
    MyService
  ]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEr Vipin SharmaView Question on Stackoverflow
Solution 1 - AngularalbanxView Answer on Stackoverflow
Solution 2 - AngularShakoor Hussain AttariView Answer on Stackoverflow
Solution 3 - AngularSunny GoelView Answer on Stackoverflow
Solution 4 - AngularJhoanView Answer on Stackoverflow
Solution 5 - AngularShashwat GuptaView Answer on Stackoverflow
Solution 6 - AngularStephaneView Answer on Stackoverflow