I have running Angular 12 application and I want to achieve a behavior to create custom ErrorHandler to handle errors globally.
Whenever I receive Error notification from backend, I subscribe it in the ToolService using this.notificationService.registerToServerCalls(......) . From here I throw the CustomException which should go to the CustomErrorHandler to handle the error. But, once the CustomException is thrown, the code is not going to the CustomErrorHandler
tool.service.ts
@Injectable()
export class ToolService {
constructor(
private notificationService: NotificationService,
@Inject(ErrorHandler) private errorHandler: CustomErrorHandler) {
this.errorHandler.onUnhandledException$.subscribe({
next: (error: ErrorDetail[]) => {
this.dialogService.open(error);
}
});
}
this.notificationRService.registerToServerCalls<ErrorDetail[]>('Error', (errorDetail: ErrorDetail[]) => {
this.onError.next(errorDetail);
throw new CustomException(errorDetail);
});
notification.service.ts
public registerToServerCalls<T>(clientMethod: string, callback: (data: T) => void): void {
this.hubConnection.on(clientMethod, callback);
}
custom-exception.model.ts
export class CustomException extends Error {
error: ErrorDetail[];
constructor(error?: ErrorDetail[]) {
super();
this.error = error;
}
}
custom-error-handler.ts
@Injectable()
export class CustomErrorHandler implements ErrorHandler {
private onUnhandledException = new Subject();
onUnhandledException$ = this.onUnhandledException.asObservable();
isErrorHandled = false;
/**
* Override the base class error handler to handle the error.
*/
handleError(errorObj) {
if (this.isErrorHandled) {
return;
}
errorObj = errorObj.rejection ? errorObj.rejection : errorObj; // .rejection is required in case of promise rejections.
let errorDetails: ErrorDetail[];
errorDetails = errorObj.error;
this.onUnhandledException.next(errorDetails);
this.isErrorHandled = true;
}
}
There is a very simple explanation for this, though I am not sure why it happens. I had somewhat the same problem recently
The problem is that Angular uses a different instance of CustomErrorHandler than the one you inject into your service.
This might be solved by using the following on your errorhandler and services but I highly doubt if that works.
@Injectable({
providedIn: 'root'
})
In my case I used a second service. Something like this:
export class ErrorMessageService {
private onUnhandledException = new Subject();
onUnhandledException$ = this.onUnhandledException.asObservable();
setMessage(message: string){
onUnhandledException.next(message);
}
}
export class CustomErrorHandler implements ErrorHandler {
constructor(private errorMessageService: ErrorMessageService)
handleError(errorObj) {
this.errorMessageService.setMessage(...)
...
...
}
}
export class ToolService {
constructor(
private notificationService: NotificationService,
private errorMessageService: ErrorMessageService)
{
this.errorMessageService.onUnhandledException$.subscribe({
next: (error: ErrorDetail[]) => {
this.dialogService.open(error);
}
});
}
}
Alternatively, you can merge the ErrorMessageService and the Toolservice and inject the toolservice in your errorhandler.