Reputation:
Hello I added a route navigation in my custom exception handler of Angular but I have the problem that when an error is triggered on the onInit of an Angular component it goes into an error loop:
Error: Cannot activate an already activated outlet
This is the code for my component:
import { ErrorHandler, Injectable, Injector } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
@Injectable()
export class ErrorService implements ErrorHandler {
constructor(
private injector: Injector
) { }
get router(): Router {
return this.injector.get(Router);
};
handleError(error: any): void {
console.error(error);
this.router.navigate(['error', { error: error }], { skipLocationChange: true});
}
}
And these my routes:
export const routes: Routes = [
{ path: '', redirectTo: 'browser', pathMatch: 'full' },
{ path: 'browser', loadChildren: './modules/browserui#BrowserUiModule' },
{ path: 'error', component: ErrorComponent, data: { title: 'Generic error' } },
{ path: '**', component: ErrorComponent, data: { title: '404 not found' } }
];
Any ideas? Thank you!
Upvotes: 5
Views: 10579
Reputation: 11
I solve it in this way:
@Injectable()
export class ErrorService {
constructor(private router: Router, private zone: NgZone) {
}
navigate(url: string) {
this.zone.run(() => this.router.navigate([url]));
}
}
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
private errorService: ErrorService;
constructor(private injector: Injector) {
}
handleError(error: Error): void {
//retarda a chamada para evitar erro de ciclo
this.errorService = this.injector.get(ErrorService);
console.log("Tratador genérico de erro.")
console.log(error);
let msg = '';
//erro de servidor
if (error instanceof HttpErrorResponse) {
if (error.status == 401) {
msg = 'Por favor, faça a login novamente.';
this.errorService.navigate('/login');
alert(msg);
}
}
}
}
Upvotes: 1
Reputation: 13214
@jonas and others, I actually found a better way to do this inside a global error handler. We don't even need a setTimeout
which in my case that wasn't enough anyway, since it was partially routing (it was routing but portion of the previous page remained on the screen, kinda strange).
Anyhow, I found a GitHub post in the Angular repo, which says to use zone
. So in my case I want to catch 401 and redirect to the login page and the code is as simple as this:
handleError(error: any) {
console.error(error);
if (error.status === 401) {
zone.run(() => router.navigate(['/login']));
}
}
Now it works as expected without any side effects.
Upvotes: 7
Reputation: 1652
I finally got this to work. My solution was to encapsulate the navigate call inside a setTimeout() function, so my solution for you would look like this:
handleError(error: any): void {
console.error(error);
setTimeout(() => this.router.navigate(['error', { error: error }], { skipLocationChange: true}));
}
Upvotes: 2