I am building a custom error handler in angular 4 to handle different kind of application error with error interceptor
create a base class( app-error.ts ) and other classes ( for eg. to handle 403 errors create class access-denied.ts ) which extend this base class.
in the base class have injected a service toastrService
and I want to display custom message from the child class BUT it gives the error on
Cannot read property 'get' of undefined
thisissue is related to OOPS concept. I do not understand how to get override parent method or call with my custom argument.
TS v 2.3.3 angular v 4.3.4
providers: [
{ provide: ErrorHandler, useClass: AppErrorHandler }
]
NOTE: AppErrorHandler class is completely different than AppError which extend angular ErorHandler interface which handle system errors.
import { Router } from '@angular/router';
import { Injectable, Injector } from '@angular/core';
import { HttpInterceptor, HttpResponse, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import {
AuthFail,
BadInput,
NotFoundError,
ServerError,
AppError,
AccessDenied,
} from '../shared/errors';
import { AuthenticationService } from './../authentication/authentication.service';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
private auth: AuthenticationService;
constructor(private router: Router, private injector: Injector) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.injector.get(AuthenticationService);
return next.handle(req).catch((err: HttpErrorResponse) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
return Observable.throw(new AuthFail(err.error));
}
if (err.status === 400) {
return Observable.throw(new BadInput(err.error));
}
if (err.status === 404) {
return Observable.throw(new NotFoundError());
}
if (err.status === 403) {
return Observable.throw(new AccessDenied());
}
return Observable.throw(new AppError(err));
}
});
}
}
import { AppError } from './app-error';
export class AccessDenied extends AppError {
constructor(public originalError?: any) {
super();
console.log('inside acces denied constructor');
// super.handleError("superrrrr"); // this also doesn't work
}
public handleError(): void {
console.log('handleError: ', );
super.handleError("Access denined error occured");
}
}
import { Inject, Injector } from "@angular/core";
import { ToastrService } from "ngx-toastr";
export class AppError {
toastrService: ToastrService;
constructor(public originalError?: any, private injector?: Injector) {
this.toastrService = this.injector.get(ToastrService);
}
// NOTE: using getter seems impossible to access in child so add the same in constructor
// get toastrService(): ToastrService {
// return this.injector.get(ToastrService);
// }
public handleError(msg: string): void {
this.toastrService.error(`Error Message: ${msg}`,
"Error", {
closeButton: true,
timeOut: 5000,
onActivateTick: true
}
);
}
}
gives error
core.es5.js:1020 ERROR TypeError: Cannot read property 'get' of undefined
at AccessDenied.AppError (app-error.ts:8)
at new AccessDenied (access-denied.ts:6)
at CatchSubscriber.eval [as selector] (error.interceptor.ts:61)
at CatchSubscriber.error (catchError.js:105)
at XMLHttpRequest.onLoad (http.es5.js:1739)
at ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.es5.js:3881)
at ZoneDelegate.invokeTask (zone.js:420)
at Zone.runTask (zone.js:188)
at ZoneTask.invokeTask [as invoke] (zone.js:496)
AccessDenied
incorrectly extends AppError
. super()
results in injector
being undefined, and injector
shouldn't be optional in AppError
constructor, because it is required.
It could be fixed by making a parameter obligatory:
constructor(private injector: Injector, public originalError?: any) {
this.toastrService = this.injector.get(ToastrService);
}
The constructor can be omitted in AccessDenied
. And should be instantiated like new AccessDenied(injector)
.
The real problem here is that AppError
does the work it isn't supposed to to. Considering that it just contains the error that can be later determined with err instanceof AppError
, it shouldn't do side effects that are currently done in handleError
.
The logic in handleError
could be moved to a method in ToastrService
or separate error service that accepts an instance of AppError
. If there's a need to provide default message for error type like Access denied error occurred
, AppError
can have public property that contains the message.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With