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
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
.
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 })]
)
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']);
}
}
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{
[...]
}
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]
}
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 {}