angularrxjsbehaviorsubjectrxjs-observablesrxjs-pipeable-operators

Rxjs Observer filter not working for error


I have the following code in my service

        let b = new BehaviorSubject({ a: undefined })
        let o = b.asObservable();
        o.pipe(filter(_ => _.a === 5)).subscribe(() => {
            debugger;
        }, error => {
            debugger
        })
        b.next({ a: 10 })
        b.next({ a: 5 })
        b.error({ a: 10 })

When I invoke b.next({a:10}) it does not hit the debugger in the onNext callback When I invoke b.next({a:5}) it hits the debugger in the onNext callback. When I invoke b.error({a:10}) it hits the debugger in the onError callback.

My expectation was the onError callback should not be called since the filter condition was not satisfied. But, clearly I have something wrong here.

How do I filter the errors too?

Thank you in advance.


Solution

  • You can't filter errors for the same reason you can't filter completes. It doesn't make sense. They signal the end of a stream. You can't filter the end.

    You can, of course, catch an error and then do nothing - which feels a bit like filtering an error.

    o.pipe(
      catchError(err => 
        err?.a === 5 ?
        return of(err) :
        EMPTY
      ),
      filter(val => val.a === 5)
    ).subscribe({
      next: val => debugger,
      error: err => debugger,
      complete: () => debugger
    });
    

    Of course, anything you send to the subject after you error or complete will do nothing.

        b.next({ a: 10 }); // Filtered, not emitted
        b.next({ a: 5 }); // value emitted
        b.error({ a: 5 }); // caught and new non-error { a: 5 } emitted as value. subject 'b' is done
        b.next({ a: 5 }); // Does nothing
    

    That final call will do nothing as the subject has errored/completed.

    Similarily:

        b.next({ a: 10 }); // Filtered, not emitted
        b.next({ a: 5 }); // value emitted
        b.complete(); // subject 'b' is done
        b.next({ a: 5 }); // Does nothing
    

    Finally:

        b.next({ a: 10 }); // Filtered, not emitted
        b.next({ a: 5 }); // value emitted
        b.error({ a: 10 }); // caught and not emitted. subject 'b' is done
        b.next({ a: 5 }); // Does nothing