6

I'm using Angular 2 RC2. I need to inject the Angular 2 Router into my custom ExceptionHandler class. However I get the following error

Error: Error: Cannot resolve all parameters for 'ErrorHandler'(?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'ErrorHandler' is decorated with Injectable.

I did try decorating private router: Router with @Inject to no avail. I'm using typescript, hence I don't think I need the @Inject attribute here.

My custom ExceptionHandler looks like this

import { ExceptionHandler } from '@angular/core';
import { Router } from '@angular/router';

export class ErrorHandler extends ExceptionHandler{

    constructor(
        private router: Router 
    ){
        super(null, null);

    }

    call(error, stackTrace = null, reason = null) {
        console.log(error);
        this.router.navigate(['/error']);
    }
}

My main.ts looks like this

import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';

import { provide, ExceptionHandler } from '@angular/core';
import { ErrorHandler } from './error-handler/error-handler';

import { HTTP_PROVIDERS } from '@angular/http';
import { ROUTER_PROVIDERS } from '@angular/router';

bootstrap(AppComponent, [
    HTTP_PROVIDERS,
    ROUTER_PROVIDERS,
    provide(ExceptionHandler, {useClass: ErrorHandler})
]);

Why am I getting this error? Isn't the Router injectable when at the time of ExceptionHandler instantiation?

The complete source code is available here

https://github.com/harindaka/angular2-seed-typescript/tree/b368315ce6608085f3154a03bc53f0404ce16495

5
  • even if it doesn't give an error. I think that it would not work (navigate) after angular throws an exception. All angular functionalities would stop. Commented Jun 17, 2016 at 11:34
  • @A_Singh That makes sense. Then what is the correct way to redirect to a custom error page with contextual error information in case of an unhandled error in the code? Commented Jun 17, 2016 at 11:52
  • I just show a custom alert box with the message, and give the choice to reload the app, or stay. Commented Jun 17, 2016 at 11:54
  • you can see my struggle to contain this Application crashes/ becomes unresponsive after encountering an exception/ error Commented Jun 17, 2016 at 11:57
  • 1
    @A_Singh Hmm I think reloading the whole application makes more sense in this scenario Commented Jun 17, 2016 at 12:07

6 Answers 6

4

See: ErrorHandler class. You can add Injectable decorator to achieve DI too!

import { ErrorHandler, Injectable } from '@angular/core';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {

  private myService: MyService;

  constructor(private injector: Injector) {
     this.myService = injector.get(MyService);
  }

  handleError(error) {
    alert('Bad things happening');
  }
  
}

@NgModule({
  providers: [
    {
      provide: ErrorHandler, 
      useClass: GlobalErrorHandler
    }
  ]
})
export class AppModule { }

Note: The above answers use ExceptionHandler which is removed in final release in favor of ErrorHandler.

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

Comments

3

Probably late to the party but this works for me (Angular 2 RC4):

import { Injectable, Injector, ExceptionHandler }    from '@angular/core';
import { Router } from '@angular/router';

@Injectable()
export class AppExceptionHandler extends ExceptionHandler {

    private router;
    injector: Injector;

    constructor(injector: Injector) {
        super(null, null);
        this.injector = injector;
    }

    call(exception: any, stackTrace?: any, reason?: string): void {
        if (this.router == null) {
            this.router = this.injector.get(Router);
        }

        // do something with the error such as spitting out to console:
        console.log('exception:', exception);
        console.log('stackTrace:', stackTrace);
        console.log('reason:', reason);

        // navigate to custom error page (defined in your routes)
        this.router.navigate(['error']);
    }
}

And then in your main.ts:

bootstrap(AppComponent, [
    HTTP_PROVIDERS,
    APP_ROUTER_PROVIDERS,
    provide(ExceptionHandler, { useClass: AppExceptionHandler })]
)

Comments

3

update ExceptionHandler was renamed to ErrorHandler https://stackoverflow.com/a/35239028/217408

orgiginal

I guess this is caused of a circular dependency. You can work around by injecting the injector and get the router imperatively:

export class ErrorHandler extends ExceptionHandler{

    private router: Router 
    constructor(inject:Injector){
        this.router = injector.get(Router);
        super(null, null);

    }

    call(error, stackTrace = null, reason = null) {
        console.log(error);
        this.router.navigate(['/error']);
    }
}

5 Comments

This did not solve it. I'm still getting the same error with your code too.
I tried to reproduce with a Plunker but I don't know how to get rid of the 3.0.0-alpha.6 router.
Did you try my suggestion together with the one from @rinukkusu?
Yes. I did. I had the same issue as you with the plunkr. You could clone the git repo in the question and give it a try
Sorry, I don't use TS locally (only Dart).
0

That's a pretty easy one - to inject into a class, you need to make the class injectable. Sounds familiar, right?

If you add a @Injectable() at the top of your ErrorHandler class, it should work.

import { ExceptionHandler, Injectable } from '@angular/core';
import { Router } from '@angular/router';

@Injectable()
export class ErrorHandler extends ExceptionHandler{
    [...]
}

6 Comments

Tried that but it doesn't solve the error either. I dont want the ErrorHandler class to be injectable. I need the Router to be injectable into the ErrorHandler class. When I add the Injectable attribute to the ErrorHandler class. I get a different error: error during instantiation of ApplicationRef_! (ApplicationRef -> ApplicationRef_)
Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'ErrorHandler' is decorated with Injectable. doesn't sound like you can get around using @Injectable(). :) - Probably the ApplicationRef error is your real problem.
Arrrgh maybe Angular 2 is beyond me. Would you be able to have a look github.com/harindaka/angular2-seed-typescript/tree/…
any luck? hope you were able to find something. I'm starting to believe this is by design and Angular 2 may not be open to injecting stuff into the exception handler.
Sadly not, this seems to be trickier, than I thought - you're probably right. I tried everything I could, but there is no way to use the injector or to inject in your ErrorHandler. :(
|
0

just had a similar problem and solved it like this (using that in the providers array of the app module):

{
  provide: ExceptionHandler,
    useFactory: (router) => {
      return new ErrorHandler(router);
    },
  deps: [Router]
}

2 Comments

Which RC version are you using?
I'm using Angular 2 RC 5. Btw, I didn't do this with Router, but with an own custom service, but that shouldn't make a difference, I hope.
0

So I ran into something similar today. My situation is a little different, I extended Http, which needed Router. However, the ErrorHandler also needed Http. Using the method above with Factories, I thought I could just inject Http into ErrorHandler. I found that when ErrorHandler invoked the Dependency Injection in the constructor for Http, Router did not exist (nor did it have all the other needed context).

So I have the injector get me an instance during the function call, and not in the constructor. Which when the injector actually tries to get the Http (in the call) it has already be created within the proper context.

CustomErrorHandler.ts:

import { ErrorHandler, Injector } from '@angular/core';
import { Http } from '@angular/http';
import { environment } from 'environments/environment';

export class CustomErrorHandler extends ErrorHandler {
  private http: Http;
  constructor(private injector: Injector) {
    super();
    // Calling this.injector.get(Http); here resulted in a null Router

    window.onerror = (msg: any, url: any, line: any, col: any, error: any) => {
      this.handleError(msg);
      return true;
    };
  }

  public handleError(error: any): void {
    try {
      // calling the injector here gave the application the time to build the correct context for the dependency injection that Http needed.
      if (!this.http) {
        this.http = this.injector.get(Http);
      }
      if (!error) {
        error = 'Unknown Error';
      }
      console.error(error);
      this.http.post('logtoserver/LogError', { Message: error.message, StackTrace: error.stack });
    } catch (exception) {
      // ignore
    }
  }
}

Relevant parts from CustomHttpService.ts:

@Injectable()
export class CustomHttpService extends Http {

  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private router: Router, private injector: Injector) {
    super(backend, defaultOptions);
  }

  request(urlOrRequest: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    // We needed Router here to call this.router.navigate(['...']);
    // ...
  }
}

app.module.ts:

import { NgModule, ErrorHandler, Injector } from '@angular/core';
import { Http, RequestOptions, XHRBackend } from '@angular/http';
import { CustomErrorHandler } from 'app/customErrorHandler';
// ...

export function customHttpServiceFactory(xhrBackend, requestOptions, router, injector) {
  return new CustomHttpService(xhrBackend, requestOptions, router, injector);
}

export function customErrorHandler(injector) {
    return new CustomErrorHandler(injector);
}

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
  ],
  providers: [
    { provide: Http, useFactory: customHttpServiceFactory, deps: [XHRBackend, RequestOptions, Router, Injector] },
    // { provide: UrlSerializer, useClass: LowercaseUrlSerializer },
    { provide: ErrorHandler, useFactory: customErrorHandler, deps: [Injector] },
    ...
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.