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 CourseComponent
s 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:
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();
}
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With