I have built an Angular 5 application which is handling errors on every single call i make. Using the HttpClient i am able to intercept the error that happens after a request to the server has been sent. The error is intercepted on a service method that send the request to the API and then when an error happens it is pushed across to the component in order to display a nice modal with the error message.
I am want to use interceptors to achieve the same behaviour in order to handle all errors on one single centralised way. But I am not sure if it is possible to communicate with the component from the interceptor class, send the message to it, so it can trigger the modal as it is currently doing, or How can I trigger the modal directly from the interceptor class.
This is my current logic:
The component:
....
export class VerificationComponent implements OnInit {
//Use to call the modal when errors happen
@ViewChild('modalError') displayErrorRef: ModalComponent;
//Method send a request to the api using a service instance _myService
getNextRecord() {
this.errorMesage = "";
this._myService.getCandidate()
.subscribe(candidate => {
this.loadCandidate = candidate;
this.userName = this.appService.getUser();
}, error => {
this.errorMesage = <any>error.errorMessage;
this.displayErrorRef.show();
});
}
}
....
The service:
.....
@Injectable()
export class MyService {
getCandidate(): Observable<ICandidate> {
return this._http.get(this._getCandidateUrl, this.jwt())
.map((response: Response) => <ICandidate>response.json())
.catch(this.handleError);
}
private handleError(error: Response) {
if (error.text())
return Observable.throw({errorMessage:error.text(),erroStatus: error.status });
else
return Observable.throw('You are not authorised to get this resource');
}
}
....
The template:
<!-- This is a child component to display the error message on the top of
this template -->
.....
<app-modal #modalError>
<div class="app-modal-header">
Error
</div>
<div class="app-modal-body">
{{errorMesage}}
</div>
<div class="app-modal-footer">
<button type="button" class="btn btn-default" (click)="hideModalError()">Logout</button>
<button type="button" class="btn btn-default"(click)="tryGetNextRecord()">Try Again</button>
</div>
</app-modal>
....
For a global error handler example that uses an HttpInterceptor you need the following.
The flow is:
app.module => register interceptor.
app.module => regsiter error service as a provider.
app.component => register global error handling that show the error modal.
YourCustomComponent => do not subscribe to the error of the Subject/Observable
Your main app.component will subscribe to any updates from the error service and display them accordingly using the modal ref.
app.module
//other code
const interceptors = [{
provide: HTTP_INTERCEPTORS,
useClass: ErrorInterceptor,
multi: true
}];
const services = [{
ErrorService
}];
@NgModule({
//other code
providers: [
interceptors,
services
],
//other code
})
error.service
@Injectable()
export class ErrorService
{
private errors = new Subject<string[]>();
constructor() { }
public addErrors = (errors: string[]): void =>
this.errors.next(errors);
public getErrors = () =>
this.errors.asObservable();
}
error.interceptor
@Injectable()
export class ErrorInterceptor implements HttpInterceptor
{
constructor(private errorService: ErrorService)
{
}
intercept(
request: HttpRequest<any>,
next: HttpHandler): Observable<HttpEvent<any>>
{
return next.handle(request).do(() => { }, (response) =>
{
if (response instanceof HttpErrorResponse)
{
if (response.status === 401)
{
return;
}
if (response.status === 400 &&
response.error)
{
this.errorService.addErrors(Array.isArray(response.error) ? response.error : [response.error]);
return;
}
this.errorService.addErrors([`Your generic error message`]);
}
return Observable.throw(response);
});
}
}
app.component
export class AppComponent implements OnDestroy
{
private ngUnsubscribe = new Subject();
@ViewChild('modalError')
displayErrorRef: ModalComponent;
constructor(private errorService: ErrorService)
{
this.initializeErrors();
}
ngOnDestroy()
{
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
private initializeErrors()
{
this
.errorService
.getErrors()
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe((errors) =>
{
//this.displayErrorRef.error = errors
this.displayErrorRef.show();
});
}
}
ngUnsubscribe is to automagicly dispose the subscription when your main app.component gets destroyed.
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