Error handling in Angular involves capturing and managing errors to ensure a smooth user experience and easier debugging. Angular provides several built-in tools and techniques for handling errors systematically.
1. Handling HTTP Errors
When making HTTP requests, you can handle errors using the HttpClient and the catchError operator from RxJS.
Example
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { catchError, throwError } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class DataService {
private apiUrl = 'https://api.example.com/data';
constructor(private http: HttpClient) {}
getData() {
return this.http.get(this.apiUrl).pipe(
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// Client-side error
console.error('Client-side error:', error.error.message);
} else {
// Server-side error
console.error(`Server-side error: ${error.status} - ${error.message}`);
}
return throwError(() => new Error('Something went wrong; please try again later.'));
}
}
- catchError: Intercepts errors and allows custom handling.
- throwError: Re-throws the error after handling it for further processing.
2. Global Error Handling
Angular provides a way to handle application-wide errors using the ErrorHandler service.
- Custom Global Error Handler.
- Create a custom error handler.
import { ErrorHandler, Injectable, NgZone } from '@angular/core';
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
constructor(private ngZone: NgZone) {}
handleError(error: any): void {
// Log the error to the console or a logging service
console.error('Global Error:', error);
// Notify the user (e.g., using a toast or modal)
this.ngZone.run(() => {
alert('An unexpected error occurred.');
});
}
}
- Register the error handler in AppModule.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { GlobalErrorHandler } from './global-error-handler';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [{ provide: ErrorHandler, useClass: GlobalErrorHandler }],
bootstrap: [AppComponent]
})
export class AppModule {}
- The service will be used throughout the entire application to catch logs.
3. Error Interceptors
Use an HTTP interceptor to handle errors globally for all HTTP requests.
Example
- Create an HTTP interceptor.
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpErrorResponse } from '@angular/common/http';
import { catchError, throwError } from 'rxjs';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
// Handle different error types
if (error.status === 404) {
console.error('Not Found:', error.message);
} else if (error.status === 500) {
console.error('Server Error:', error.message);
}
// Optionally, rethrow the error
return throwError(() => new Error('An error occurred. Please try again later.'));
})
);
}
}
- Register the interceptor in AppModule.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AppComponent } from './app.component';
import { ErrorInterceptor } from './error-interceptor';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: ErrorInterceptor,
multi: true
}
],
bootstrap: [
AppComponent
]
})
export class AppModule {}
4. Using Angular Guards for Route Error Handling
Angular guards can protect routes and handle access-related errors.
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(): boolean {
const isAuthenticated = false; // Replace with actual authentication logic
if (!isAuthenticated) {
alert('You are not authorized to access this page.');
this.router.navigate(['/login']);
return false;
}
return true;
}
}
5. Error Display in the UI
Display user-friendly error messages in the UI using Angular components.
Example
- Create an error message component.
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-error-message',
template: `
<div *ngIf="errorMessage" class="error">
{{ errorMessage }}
</div>
`,
styles: [
`
.error {
color: red;
}
`,
],
})
export class ErrorMessageComponent {
@Input() errorMessage: string | null = null;
}
- Use the component.
<app-error-message [errorMessage]="error"></app-error-message>
6. RxJS Error Handling Strategies
- Retry Failed Requests.
import { retry } from 'rxjs';
this.http.get(this.apiUrl).pipe(
retry(3), // Retry up to 3 times
catchError(this.handleError)
);
- Fallback Data.
this.http.get(this.apiUrl).pipe(
catchError(() => of([])) // Return fallback data on error
);
7. Logging Errors
Use external services like Sentry, LogRocket, or custom logging services to log errors.
Example
@Injectable({
providedIn: 'root'
})
export class LoggingService {
logError(message: string, stack: string) {
// Send error logs to an external server
console.log('Logging error:', message);
}
}
Summary
- HTTP Errors: Use catchError to handle API errors.
- Global Error Handling: Implement a custom ErrorHandler.
- Interceptors: Handle HTTP errors globally.
- Guards: Handle access-related errors.
- Error Messages: Display user-friendly errors in the UI.
- RxJS: Use operators like retry or catchError for advanced error handling.
- Logging: Integrate external logging services.
This article will help to understand error handling in different ways and hope it will help in your application.