5

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!

3
  • 1
    What do you mean by "when an error is triggered on the onInit"? What kind of error is triggered in what component? Commented Feb 28, 2017 at 7:59
  • Here is an example: if (undefined === this.items) { throw new Error('Attribute items is required'); }. In the OnInit of the component we control that the Inputs have value Commented Mar 1, 2017 at 8:46
  • I've got the same issues, errors thrown in OnInit does not route as theres some Components (3rd party) that cannot unsubscribe their subscribers... Did you find a solution to this issue? Commented Oct 12, 2017 at 6:58

3 Answers 3

7

@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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! This one should be accepted as correct answer!
2

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}));
  }

  • Angular: 4.4.4
  • Angular-cli: 1.4.6
  • Typescript: 2.5.3

Comments

1

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);
      }
    }   
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.