Angular ThrowError operator returns an observable, which on subscription immediately errors out. It does not emit any results.
ThrowError creates a new observable. Hence we must subscribe to it. The following example creates an ThrowError observable and then subscribes to it.
import { Component, VERSION } from "@angular/core";
import { Observable, of, from, throwError } from "rxjs";
import { map, catchError } from "rxjs/operators";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
name = "Angular " + VERSION.major;
obs = throwError("Error From ThrowError observable");
ngOnInit() {
this.obs.subscribe(
el => {
console.log("Value Received :" + el);
},
err => {
console.log("Error caught at Subscriber :" + err);
},
() => console.log("Processing Complete")
);
}
}
****Console Window
Error caught at Subscriber: Error From ThrowError observable
First, we create an observable using throwError. The first argument to the throwError is the error object. This error object is passed to the consumers when it raises the error notification.
obs = throwError("Error From ThrowError observable")
We, subscribe to it in the ngOnInit method.
this.obs.subscribe(
The observable immediately raises the error notification and completes. The error callback is invoked and we will see the error message in the console window.
err => {
console.log("Error caught at Subscriber :" + err);
},
It is very easy confuse between the Throw Error With ThrowError.
Throw Error throws an error. It is a JavaScript construct and is not part of the RxJs. We need to use the try/catch block to catch the errors thrown from the Throw Error. The RxJS uses the try/catch block to catch any errors thrown from the observables. And when they catch one, they emit an error notification (raises the error callback), and then the observable stops.
ThrowError does not throw errors like throw Error. It returns a new observable, which emit an error notification (raises the error callback), and then stops.
import { Component, VERSION } from "@angular/core";
import { Observable, of, from, throwError } from "rxjs";
import { map, catchError } from "rxjs/operators";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
srcArray = from([1, 2, "A", 4]);
obs = this.srcArray.pipe(
map(val => {
let result = (val as number) * 2;
if (Number.isNaN(result)) {
console.log("Error in the observable");
throw Error("Not a Number");
}
return result;
})
);
ngOnInit() {
this.obs.subscribe(
el => {
console.log("Value Received :" + el);
},
err => {
console.log("Error caught at Subscriber :" + err);
},
() => console.log("Processing Complete.")
);
}
}
***Console ****
Value Received :2
Value Received :4
Error in the observable
Error caught at Subscriber :Error: Not a Number
The observable emits values 2 & 4.
When map operators receive the value A it uses throw Error to throw an error. The observable catches this error and raises the error notification and terminates.
The last value 8 is never emitted.
Now, let us replace the throw Error with return throwError
import { Component, VERSION } from "@angular/core";
import { Observable, of, from, throwError } from "rxjs";
import { map, catchError } from "rxjs/operators";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
name = "Angular " + VERSION.major;
srcArray = from([1, 2, "A", 4]);
obs = this.srcArray.pipe(
map(val => {
let result = (val as number) * 2;
if (Number.isNaN(result)) {
console.log("Error in the observable");
return throwError("Not a Number");
}
return result;
})
);
ngOnInit() {
this.obs.subscribe(
(el: any) => {
console.log("Value Received :" + el);
},
err => {
console.log("Error caught at Subscriber :" + err);
},
() => console.log("Processing Complete.")
);
}
}
****Console ********
Value Received :2
Value Received :4
Error in the observable
Value Received :[object Object]
Value Received :8
Processing Complete
The observable emits values 2 & 4.
When the map operator receive the value A it returns throwError. Remember throwError returns an observable. It will raise the error notification, only if you subscribe to it.
The map operator does not subscribe to the observable. It just returns it to the subscriber.
Hence the subscriber receives the throwError observable as value. Hence you see [object Object] in the console.
Since there is no error raised, the observable continues and emits the next value 8 and then completes.
The throwError needs to be subscribed for it to emit error notification. We can use it to compose with other Observables such as mergeMap, switchMap, catchError etc.
The following example, shows how to use ThrowError with CatchError
import { Component, OnInit } from "@angular/core";
import { throwError, from } from "rxjs";
import { map, catchError } from "rxjs/operators";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
srcArray = from([1, 2, "A", 4]);
obs = this.srcArray.pipe(
map(val => {
let result = (val as number) * 2;
if (Number.isNaN(result)) {
console.log("Errors Occurred in Stream");
throw new Error("Result is NaN");
}
return result;
}),
catchError(error => {
console.log("Caught in CatchError. Throwing error");
return throwError(error);
})
);
ngOnInit() {
this.obs.subscribe(
el => {
console.log("Value Received " + el);
},
err => {
console.log("Error caught at Subscriber " + err);
},
() => console.log("Processing Complete.")
);
}
}
******* CONSOLE *******
Value Received 2
Value Received 4
Errors Occurred in Stream
Caught in CatchError. Throwing error
Error caught at Subscriber Error: Result is NaN
The code throws the error using throw error in map operator.
CatchError will catch this error. We use the CatchError to handle the errors thrown by the Angular Observable. Once we handle the error, we must return an observable. We can either return a replacement observable or return an error. The observable returned from CatchError is immediately subscribed.
Hence we can use the throwError here, which is immediately subscribed , which in turn emits an error notification
catchError(error => {
console.log("Caught in CatchError. Throwing error");
return throwError(error);
})
The Angular MergeMap maps each value from the source observable into an inner observable, subscribes to it, and then starts emitting the values from it.
In the following example, we use throwError to return a observable, when we receive the value 3. The MergeMap subscribes to this new observable and raises the error notification and stops.
import { Component, OnInit } from "@angular/core";
import { throwError, of } from "rxjs";
import { map, mergeMap, catchError } from "rxjs/operators";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
srcObservable = of(1, 2, 3, 4);
innerObservable = of("A", "B");
obs = this.srcObservable.pipe(
mergeMap(val => {
console.log("Source value " + val);
console.log("starting new observable");
if (val == 3) return throwError("Error in observable");
return this.innerObservable;
})
);
ngOnInit() {
this.obs.subscribe(
el => {
console.log("Value Received " + el);
},
err => {
console.log("Error caught at Subscriber " + err);
},
() => console.log("Processing Complete.")
);
}
}
***Console ****
Source value 1
starting new observable
Value Received A
Value Received B
Source value 2
starting new observable
Value Received A
Value Received B
Source value 3
starting new observable
Error caught at Subscriber Error in observable