I'm a bit confused by the rxjs catchError
operator. Here is a simple example using Angular:
(live demo here)
import { Component } from '@angular/core';
import { of, timer } from 'rxjs'
import { tap, catchError } from 'rxjs/operators'
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
})
export class AppComponent {
constructor() {
const source$ = timer(1000, 1000).pipe(tap(n => {
if (n === 3) {
throw new Error('n === 3')
}
}))
this.value$ = source$.pipe(catchError(err => {
return of(42)
}))
}
value$
}
{{ value$ | async }}
The source$
observable to which the async pipe subscribes emits 0,1,2 and then errors. This error is caught in the catchError
operator which swallows the error silently and emits 42. This I think I understand. However, the emission then stops (I was expecting 4,5,6,...). Can someone please explain why this does not occur and if there is any way of achieving such a behaviour?
This matters to me in practice in a situation such as below, where we load fresh data every time the route params emit. Supposing we navigate to a route that throws an error (e.g. 404, 500,...) I do not want the event stream to stop emitting as then I am left unable to navigate back to any other page. I just want to handle the error gracefully and keep listening for route changes.
this.foo$ = this._route.params.pipe(
map(params => params.id),
switchMap(id => this._fooServerClient.getOneById(id)),
catchError(err => {
return of(undefined)
})
)