Angular 7 routerLink directive warning 'Navigation triggered outside Angular zone'
Asked Answered
C

5

24

I am struggling with Angular framework to get my application run smoothly, but I can't resolve an issue with routing. I have a top level AppComponent and app-routing.module.ts which manage the navigation via my custom SlideMenuComponent. My simplified html template of AppComponent:

<app-slide-menu [buttons]="menuButtons"></app-slide-menu>
<router-outlet></router-outlet>

My SlideMenuComponent has the following html as its core:

<nav><div *ngFor="let button of buttons">
    <a routerLink="{{button.routerLink}}"
    >{{button.name}}</a>
</div></nav>

A user can navigate to '/courses' through this slide menu, which is supervised by CoursesComponent that paginates links to a particular CourseComponents that are retrieved from the server. These components reside in their own courses.module.ts module whith their own courses-routing.module.ts. But when I click any of those links I get Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'? console warning, ngOnInit() is not called for openned CourseCompontent, and it doesn't update untill I click any of the buttons on the page. I had this issue when manually navigating via router.navigate() that was resolved by forwarding this task to NgZone.runTask(router.navigate()), but why does this happen with anchor tags and routerLink direcrives? Here is my CoursesComponent code excerpt:

<nav><ul>
        <li *ngFor="let course of api.data | paginate: {
            currentPage: currentPage, itemsPerPage: limit, totalItems: api.total
        }">
           <a
               [routerLink]="course._id"
               [queryParams]="{ page: '1', limit: '5' }"
           >
            {{course.name}} ({{course.description}})
           </a>
        </li>
</ul></nav>

A gif to demonstrate the issue:

enter image description here

Contingent answered 3/11, 2018 at 17:0 Comment(11)
Can you try this code <nav><div *ngFor="let button of buttons"> <a [routerLink]="[button.routerLink]" >{{button.name}}</a> </div></nav>Garbanzo
@Suresh Sorry, maybe it is a bit misleading, but this code works fine, its my slide menu links, though I tried to change its interpolation type but nothing effectively changes. The issue arises when I click <a [routerLink]="course._id" [queryParams]="{ page: '1', limit: '5' }" > {{course.name}} ({{course.description}}) </a>Contingent
RouteLink should be defined in [] bracket. [routerLink]="[course._id]".Garbanzo
@Suresh Tried, but no changes. Indeed routerLink may be just a string, not an array of pathsContingent
instead of routerlink, can you try caling click function and use navigateByURL as one option1 or instead of relative path, try to give absolute path '/courses/id'Garbanzo
@Suresh yeah, I may use it as a workaround, but why does this happen?Contingent
did you tried absolute path? whether it works?Garbanzo
@Suresh I tried [routerLink]="['/courses', course._id]" But it didn't helpContingent
might be isuue with anchor tag it seems. if you use anchor, we need to use click event.Garbanzo
Strange issue. Can you show the paginate pipe and how you resolve api.data?Ptolemaeus
@PierreDuc Here is a gist of my component anchored to function where I get courses from the server. Paginate pipe is from ngx-pagination npm moduleContingent
S
40

It seens a bug, try this as an workaround

constructor(private ngZone: NgZone, private router: Router) {}

public navigate(commands: any[]): void {
    this.ngZone.run(() => this.router.navigate(commands)).then();
}
Subjective answered 8/11, 2018 at 18:21 Comment(7)
worked like a charm, thanks. any problems to be expected by this solution?Bostick
Thanks calebeaires. It works also for my case. I my case, it happened while navigating into Angular7 route from angularJs in a Angular7 & AngularJs hybird upgrade app.Mistrust
This give me "ngZone is not defined"Stover
@VincentGuyard, add this to your imports: import { Component, OnInit, ..., NgZone } from '@angular/core';Necklace
There could be multiple comportment in the application, do i need to put given code in all those components ?Hezekiah
For me I'm using FCM push notification in an Ionic chat app I built. When the user gets the notification they click the icon and the app opens but it doesn't take them to the specified page. I tried using this method to no avail.Evenhanded
Workaround works but feels like a hack and I can't figure what cause it.Sihun
F
7

We had encountered this bug when we were navigating somewhere in our solution.

In our sidebar component we use on-push change detection and we have had one this.ref.detectChanges() when routing occured (change of parameters), which somehow broke routing (possibly kicking parallel running resolvers out of ngZone or something similar). After changing this to the anyway preferred this.ref.markForCheck() this bug didn't appear again. I'm happy we didn't need a workaround, weird behavior though..

Hope this helps anyone having the same issue.

Fokine answered 21/2, 2019 at 8:25 Comment(0)
D
5

Since there is no accepted answer, and since I found, using Angular 8, the top ranked answer does not quite work, and needs a little more explanation, I have the following to add:

My specific issue was with ag-grid, but I suspect any place where a component is injected, within an *ngFor or otherwise, can potentially cause this problem. This is very close to the previous answer, but instead declares a string parameter into the navigate function and then calls navigateByUrl instead of navigate.

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

@Component({
  template: `<tag (click)="navigate(path)">clickable text</tag>`
})

constructor(private ngZone: NgZone, private router: Router) { }

public navigate(path: string): void {
  this.ngZone.run(() => this.router.navigateByUrl(path)).then();
}

Your mileage may vary, but this worked beautifully for me.

Dylandylana answered 17/2, 2020 at 6:46 Comment(5)
I'm trying this in my Ionic 4 (Angular) app when opening a push notification but is not making any result, still throwing the same warning and keeps stuck in the main page, any idea??Thunderpeal
@HamletMinjares - No ideas. Are you sure you are following this pattern exactly? The (click) event must call the component's navigate function as shown; it cannot use routerLink any longer. Other than that, I would think this would work fine in Ionic. I can't see why that would make a difference, but I don't have a lot of experience with Ioninc.Dylandylana
I apologize; I was using a guard class to validate before call this method and didn't noticed that this guard was redirecting without ng zone. Just after I correted that, it worked like a charm, thank you!Thunderpeal
your answer helped me with my issue. despite using angular 10 instead of 8, it worked perfectlyDorfman
Same issue with me also seems to be related to ag-grid rendering a template. I may do this as a temporary workaround, but I'd really like to get it working consistently with [routerLink] because I'd like it to be a true link that can be opened in another tab if the user chooses to.Basicity
R
1

For me, this error was because of a part of the code running outside the NgZone. After which we had a this.ref.detectChanges() running to detect changes. The changes detected would change the DOM and put <a [routerLink]="..."></a>. This use to break the routing. Solution : We ran the part of code outside NgZone inside NgZone but using this.ngZone.run . This way we did not have to use ref.detectChanged() as the changed(RxJS Subject subscribe) were in NgZone. This solved the routing issue.

Hope this helps anyone having the same issue.

Rothmuller answered 25/4, 2020 at 7:14 Comment(1)
thanks! save me lot's of debugging hoursKibe
M
-1

Working Example - Refer this

 public backButtonSubscription;
      ngAfterViewInit(): void {
        let self = this;
        this.backButtonSubscription = this.platform.backButton.subscribe(() => {
          console.log("back preseed \n \n");
    
          self._ngZone.runOutsideAngular(() => {
            setTimeout(() => {
              self.Router.navigateByUrl("/stock-management");
            }, 100);
          });
        });
      }
Materi answered 16/7, 2021 at 20:47 Comment(1)
OP is using routerLink, this is a copy-paste from another of your answers: https://mcmap.net/q/174067/-navigation-triggered-outside-angular-zone-did-you-forget-to-call-39-ngzone-run-39Spondee

© 2022 - 2024 — McMap. All rights reserved.