Angular catchError
November 26, 2018
This page will walk through Angular RxJS catchError
example. RxJS catchError
operator catches the error thrown by Observable
and handles it by returning a new Observable
or throwing user defined error. catchError
is the changed name of catch
starting from RxJS 5.5. Angular 6 integrates RxJS 6 and hence Angular 6 onwards we need to use RxJS catchError
operator to handle error. catchError
is the pipeable operator and it is used within pipe
function of Observable
. The parameter of catchError
is a function that takes error as argument and returns Observable
instance. catchError
is imported as following.
import { catchError } from 'rxjs/operators';
catchError
examples. We will understand the difference between catchError
and subscribe
error callback and we will also provide catchError
examples with throwError
and retry
operators.
Contents
Technologies Used
Find the technologies being used in our example.1. Angular 7.0.0
2. Angular CLI 7.0.3
3. TypeScript 3.1.1
4. Node.js 10.3.0
5. NPM 6.1.0
6. RxJS 6.3.3
7. In-Memory Web API 0.6.1
Observable and catchError
Observable
works asynchronously and once there is an error in Observable
for any element then it stops emitting other values. To handle Observable
error, we can use catchError
operator. We use catchError
for logging a proper message and to throw user defined error or instance of Observable
with default data. Using catchError
does not mean that Observable
will emit other values which have not been emitted because of error. Let us understand by example.
Look into the code.
of("A", "B", "C", "D", "E").pipe( map(el => { if (el === "C") { throw new Error("Error occurred."); } return el; }) ).subscribe(el => console.log(el), err => console.error(err), () => console.log("Processing Complete.") );
A B Error: "Error occurred."
subscribe
. In the subscribe
, first callback is to get result, second callback is to log error if any, third callback is to log completion. Once source Observable
throws error, it stops emitting rest of the values it has.
In
subscribe
if second callback for error executes then the third callback for completion does not execute and if third callback for completion executes, it means there is no error or error is handled by catchError
in source Observable
. If we throw error from catchError
then in subscribe
, second callback for error will execute and third callback for completion will not execute.
If we want to handle error before
subscribe
then we need to use catchError
that handles the error in source Observable
and returns new instance of Observable
that can be subscribed.
of("A", "B", "C", "D", "E").pipe( map(el => { if (el === "C") { throw new Error("Error occurred."); } return el; }), catchError(err => { console.error(err.message); console.log("Error is handled"); return of("Z"); }) ).subscribe(el => console.log(el), err => console.error(err), () => console.log("Processing Complete.") );
A B Error occurred. Error is handled Z Processing Complete.
catchError and throwError
After caching error either we can returnObservable
instance with default data or can throw error using RxJS throwError
. throwError
emits error notification immediately. Find the code snippet using catchError
and throwError
.
of("A", "B", "C", "D", "E").pipe( map(el => { if (el === "C") { throw new Error("Error occurred."); } return el; }), catchError(err => { console.error(err.message); console.log("Error is handled"); return throwError("Error thrown from catchError"); }) ).subscribe(el => console.log(el), err => console.error(err), () => console.log("Processing Complete.") );
A B Error occurred. Error is handled Error thrown from catchError
catchError
block we have returned error using throwError
. The error message is shown by error callback of subscribe
.
retry and catchError
RxJS providesretry
operator that resubscribes the Observable
for the given number of count when there is an error. Before throwing error Observable
is resubscribed for the given number of count by retry
operator and if still there is an error, then error is thrown. retry
is useful to hit the URL many times. It is possible that because of network bandwidth, URL does not return successful data in one time and when it reties, it may return data successfully. If after retying still there is error in Observable
then catchError
can be used to return Observable
with user defined default data.
Find the sample code to use
retry
with catchError
.
getBook(id: number): Observable<Book> { return this.http.get<Book>(this.bookUrl + "/" + id).pipe( retry(3), catchError(err => { console.log(err); return of(null); }) ); }
Complete Example
book.component.tsimport { Component, OnInit } from '@angular/core'; import { Observable, of, pipe, throwError } from 'rxjs'; import { map, switchMap, debounceTime, catchError } from 'rxjs/operators'; import { BookService } from './book.service'; import { Book } from './book'; import { FormControl, FormBuilder, FormGroup } from '@angular/forms'; @Component({ selector: 'app-book', template: ` <h3>Search Book</h3> <form [formGroup]="bookForm"> ID: <input formControlName="bookId"> </form> <br/> <div *ngIf="book"> Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}} </div> ` }) export class BookComponent implements OnInit { book: Book; constructor(private bookService: BookService, private formBuilder: FormBuilder) { } ngOnInit() { this.searchBook(); of("A", "B", "C", "D", "E").pipe( map(el => { if (el === "C") { throw new Error("Error occurred."); } return el; }), catchError(err => { console.error(err.message); console.log("Error is handled"); return throwError("Error thrown from catchError"); }) ).subscribe(el => console.log(el), err => console.error(err), () => console.log("Processing Complete.") ); } bookId = new FormControl(); bookForm: FormGroup = this.formBuilder.group({ bookId: this.bookId } ); searchBook() { this.bookId.valueChanges.pipe( debounceTime(500), switchMap(id => { console.log(id); return this.bookService.getBook(id); }) ).subscribe(res => this.book = res); } }
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { Book } from './book'; import { catchError, retry } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class BookService { bookUrl = "/api/books"; constructor(private http: HttpClient) { } getBook(id: number): Observable<Book> { return this.http.get<Book>(this.bookUrl + "/" + id).pipe( retry(3), catchError(err => { console.log(err); return of(null); }) ); } }
export interface Book { id: number; name: string; category: string; }
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <app-book></app-book> ` }) export class AppComponent { }
import { InMemoryDbService } from 'angular-in-memory-web-api'; export class TestData implements InMemoryDbService { createDb() { let bookDetails = [ { id: 101, name: 'Angular by Krishna', category: 'Angular' }, { id: 102, name: 'Core Java by Vishnu', category: 'Java' }, { id: 103, name: 'NgRx by Rama', category: 'Angular' } ]; return { books: bookDetails }; } }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; import { BookComponent } from './book.component'; //For InMemory testing import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; import { TestData } from './test-data'; @NgModule({ imports: [ BrowserModule, HttpClientModule, FormsModule, ReactiveFormsModule, InMemoryWebApiModule.forRoot(TestData) ], declarations: [ AppComponent, BookComponent ], providers: [ ], bootstrap: [ AppComponent ] }) export class AppModule { }
Run Application
To run the application, find the steps.1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Install angular-in-memory-web-api@0.6.1
4. Run ng serve using command prompt.
5. Access the URL http://localhost:4200
Find the print screen of the output.

References
RxJS catchErrorAngular: The RxJS library
Pipeable Operators