My Angular 9 app has a CustomErrorHandler, and an ErrorPageComponent. When any exception is thrown throughout the app, the CustomErrorHandler will tell the router to navigate to ErrorPageComponent. However, there is a button inside ErrorPageComponent which could throw its own exception, in which case I want CustomErrorHandler to still tell the router to navigate to ErrorPageComponent, as is normal. However, when ErrorPageComponent is routed to itself in this way, it needs to call its initialization method a second time.
Normally, if you want a component to call an initialization method after routing to itself, you can simply subscribe to the routing event. Then, as long as you have correctly set onSameUrlNavigation to reload, when the component navigates to itself, the router will trigger a routing event will call whichever callback method your component has used to subscribe to it.
However, when my CustomErrorHandler tells the router to navigate to ErrorPageComponent, no routing event is triggered.
This will make more sense if you look at the code:
Here's my route config inside app-routing.module.ts:
const routes: Routes = [
{ path: 'normal', component: NormalComponent},
{ path: '', redirectTo: '/normal', pathMatch: 'full'}
];
const volitileRoutes: Routes = [
{ path: 'error', component: ErrorPageComponent}
];
const fallbackRoute: Routes = [
{ path: '**', component: Error404PageComponent }
];
@NgModule({
imports: [
RouterModule.forRoot(routes),
RouterModule.forRoot(volitileRoutes, {onSameUrlNavigation: 'reload'}), // I've correctly set onSameUrlNavigation
RouterModule.forRoot(fallbackRoute)
],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here is the CustomErrorHandler which will redirect to the ErrorPageComponent:
@Injectable({
providedIn: 'root'
})
export class CustomErrorHandler extends ErrorHandler {
constructor(private ngZone: NgZone, private router: Router){
super();
}
handleError(error: any){
// error handling code here
console.log('error caught'); // I've confirmed that my CustomErrorHandler is in fact handling errors.
/* This is not the normal way to do navigation. But for reasons I don't understand, this
is the only way to get navigation to work from within an ErrorHandler; you cannot simply
call router.navigate like normal from within an ErrorHandler. */
this.ngZone.run(() => this.router.navigate(['/error']));
}
}
Finally, here is ErrorPageComponent:
@Component({
selector: 'app-error-page',
templateUrl: './error-page.component.html',
styleUrls: ['./error-page.component.css']
})
export class ErrorPageComponent implements OnInit, OnDestroy {
private navSubscription = new Subscription();
constructor(private router: Router) { }
ngOnInit(): void {
this.navSubscription = this.router.events.subscribe((e: any) => {
console.log('route event triggered'); // this line is never reached
if (e instanceof NavigationEnd) {
// do initialization code
}
});
}
ngOnDestroy(): void {
this.navSubscription?.unsubscribe(); // this prevents a memory leak
}
}
As I mentioned in my code comments, I've confirmed that CustomErrorHandler is correctly handling the error, and is calling the router navigation method. However, the subscription callback method passed to the router navigation event is never called. What am I doing wrong? How do I subscribe to routing events in ErrorPageComponent?