Angular throwError

By Arvind Rai, February 18, 2019
RxJS throwError operator is used to create an Observable that emits an error notification immediately and no element. throwError can be used composing with other Observable, such as in a mergeMap, switchMap etc. throwError is introduced in RxJS 6 and we need to use it in place of Observable.throw(). Angular 6 has integrated RxJS 6 and Angular 6 onwards we can use throwError that will return Observable instance with error message. We catch error using catchError returned by throwError.
throwError is imported as following.
import { throwError } from 'rxjs'; 
Here on this page we will discuss using RxJS throwError with examples step by step.

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

Using throwError

Let us understand how to use throwError operator.
Example-1:
In this example, the Observable instance will emit 1,2,3,4 but for the number 3, we will throw error.
  of(1,2,3,4).pipe(
	mergeMap(data => {
	  if (data === 3) {
		return throwError('Error Occurred for data: '+ 3);
	  }
	  return of(data);
	})
  ).subscribe(res => console.log(res),
	 err => console.error(err)
  ); 
Output will be
1 2
Error Occurred for data: 3 
Example-2:
Here we will emit numbers after every 2 seconds and for number 2, an error is thrown.
  interval(2000).pipe(
	mergeMap(x => x === 2
	  ? throwError('Error: Received 2')
	  : of('a', 'b')
	),
  ).subscribe(x => console.log(x),
	e => console.error(e)
  ); 
Find the output.
a b a b 
Error: Received 2 

throwError, retry and catchError

Here we will create an example with throwError, retry and catchError.
of("A", "B").pipe(
  switchMap(el => {
	if (el === "B") {
	 return throwError("Error occurred.");
	}
	return el;
  }),
  retry(2),
  catchError(err => {
	console.error(err);
	return throwError("User defined error.");
  })
).subscribe(el => console.log(el),
	err => console.error(err),
	() => console.log("Processing Complete.")
); 
Find the output.
A A A
Error occurred.
User defined error. 
When the source Observable emits element B, error is thrown by throwError. The operator retry resubscribes 2 times and finally error is caught by catchError operator and then we again throw user defined error using throwError. Process complete block will not execute because error occurs.

JavaScript throw vs RxJS throwError

JavaScript throw statement throws user-defined exception. throw does not return Observable instance. Find the sample code snippet for throw.
switchMap(el => {
  if (el === "B") {
    throw new Error("Error occurred.");
  }
  return el;
}) 
RxJS throwError() returns Observable instance that emits only error and no element. Find the sample code for throwError().
switchMap(el => {
  if (el === "B") {
    return throwError("Error occurred.");
  }
  return el;
}) 

Complete Example

book.component.ts
import { Component, OnInit } from '@angular/core';
import { of, throwError, interval } from 'rxjs';
import { switchMap, debounceTime, catchError, retry, mergeMap } 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() {
      of(1,2,3,4).pipe(
        mergeMap(data => {
          if (data === 3) {
            return throwError('Error Occurred for data: '+ 3);
          }
          return of(data);
        })
      ).subscribe(res => console.log(res),
         err => console.error(err)
      );

      interval(2000).pipe(
        mergeMap(x => x === 2
          ? throwError('Error: Received 2')
          : of('a', 'b')
        ),
      ).subscribe(x => console.log(x),
         e => console.error(e)
      );

      //-------------------------
      this.retryAndHandleError();
      this.searchBook();
   }

   retryAndHandleError() {
    of("A", "B").pipe(
      switchMap(el => {
        if (el === "B") {
         return throwError("Error occurred.");
        }
        return el;
      }),
      retry(2),
      catchError(err => {
        console.error(err);
        return throwError("User defined error.");
      })
    ).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(1000),
      switchMap(id => {
        return this.bookService.getBook(id);
      }),
      catchError(err => {
        return throwError('User defined error.');
      })
    ).subscribe(res => this.book = res,
        err => {
          console.error(err);
          this.book = null;
          this.searchBook();
        }
    ) 
  }
} 
book.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Book } from './book';

@Injectable({
    providedIn: 'root'
})
export class BookService {
    bookUrl = "/api/books";	
    constructor(private http: HttpClient) { }
    getBook(id: number): Observable<Book> {
      let url = this.bookUrl + "/" + id;   
      return this.http.get<Book>(url);
    }  
} 
book.ts
export interface Book {
   id: number;
   name: string;
   category: string;
} 
app.component.ts
import { Component } from '@angular/core';

@Component({
   selector: 'app-root',
   template: `
    <app-book></app-book>
   `
})
export class AppComponent { 
} 
test-data.ts
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 };
  }
} 
app.module.ts
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
We can see output in console as following.
Angular throwError

References

RxJS throwError
Angular RxJS retry
Angular catchError

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI









©2023 concretepage.com | Privacy Policy | Contact Us