BehaviorSubject used as PartialObserver breaks the subscription on BehaviorSubject
Asked Answered
J

1

5

I was looking through the interfaces of observables and saw you can pass anything that implements PartialObserver to the subscribe function. So I did that with BehaviorSubject.

Like this (A)

source$
      .pipe(
        tap(() => console.log('X')),
      )
      .subscribe(this._titlesX$);

So I did, but found something very strange. If I pass the behavior subject to the subscribe function the values get emitted, but to see that, you have to subscribe before using the BehaviorSubject as PartialObserver.

In the docs for BehaviorSubject you can find this:

A variant of Subject that requires an initial value and emits its current value whenever it is subscribed to.

So when using BehaviorSubject as partialObserver this behavior breaks.(No pun intended)

But when I use this method: Like this (B)

source$
     .pipe(
        tap(() => console.log('X')),
      )
      .subscribe(res => this._titlesX$(res));

Everything works as expected.

Why does method A not work? Is this a bug or am I just using it wrong?

Here is a link to the stackblitz all setup. Link to stackblitz project

titleX: represents method A titleY: represents method B

Subscribing with an BehaviorSubject should be possible. And the time when you subscribed should not matter. Otherwise it shouldn't be allowed as a parameter for the subscribe method.

Jaquenette answered 14/8, 2019 at 17:4 Comment(5)
While I admit this is fairly curious behaviour from an Observable that should re-emit its latest emission when subscribed to, I can't really see why you'd pass a BehaviorSubject to the subscribe function. Are you just experimenting or do you have something specific in mind?Ink
@WillAlexander I do this all the time. It's handy for wanting to cache a result.Robbinrobbins
Out of curiosity, any reason for putting it in the subscribe and not in a tap or a custom operator?Ink
rxjs has many many multicasting operators. putting it in subscribe is the most straightforward way though if you want to fully connect one subject to another, as it auto passes onNext, onError and onCompleteRobbinrobbins
@WillAlexander I have an httpClient response. I map some stuff. And pass the result to the BehaviorSubject. So we can have access the next etc. regarding 2q: I don't want my observables to have side effects.Jaquenette
R
6

the reason is because when you do

source$.subscribe(this._titlesX$)

you've fully casted the source to the BehaviorSubject, as BehaviorSubject is a full observer, including the complete and error handlers. of completes after one emission, so it also completes your BehaviorSubject, and completed subjects do not emit. but just calling next in the subscribe of source$ clearly doesn't pass through the complete / error handlers.

if your source was more like:

const source$ = interval(1000).pipe(map(v => [v.toString()]));

where it does not complete, you'll see expected behavior.

blitz: https://stackblitz.com/edit/angular-gfmdgf?file=src/app/app.component.ts

Robbinrobbins answered 14/8, 2019 at 18:26 Comment(1)
I couldn't understand why I was able todo .subscribe(myBehaviorSubject) on some pipelines, and why I couldn't on others. This makes complete sense now. Thank you for sharing!Marginal

© 2022 - 2024 — McMap. All rights reserved.