RxJS 5, converting an observable to a BehaviorSubject(?)
shareReplay
should do what you want:
import 'rxjs/add/operator/shareReplay';
...
theValue$: Observable<boolean> = parent$.shareReplay(1);
shareReplay
was added in RxJS version 5.4.0. It returns a reference counted observable that will subscribe to the source - parent$
- upon the first subscription being made. And subscriptions that are made after the source completes will receive replayed notifications.
shareReplay
- and refCount
in general - is explained in more detail in an article I wrote recently: RxJS: How to Use refCount.
This is an improved variant of the tmuechsch's answer.
import { Observable, BehaviorSubject } from 'rxjs';
export function convertObservableToBehaviorSubject<T>(observable: Observable<T>, initValue: T): BehaviorSubject<T> {
const subject = new BehaviorSubject(initValue);
const subscription = observable.subscribe(subject);
return {
subject,
stopWatching: () => subscription.unsubscribe()
};
}
Be careful because the returned subject never unsubscribes from the source observable. You need to call stopWatching
manually when you know that there are no more references to subject
(e.g. when a view component is destroyed/unmounted). Otherwise you'll get a memory leak.
It's impossible to make an absolutely safe solution for the given problem. The reason is that a behavior subject has a value
attribute that must always be updated even if the subject isn't subscribed to, therefore you can't unsubscribe from observable
automatically when everybody unsubscribes from subject
.
The cartant's solution isn't perfect too, because the result is not instanceof BehaviorSubject
and shareReplay
records the values only when it's subscribed to.
I've implemented a method to convert Observables to BehaviorSubjects, as I think that the shareReplay method isn't very readable for future reference.
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
export function convertObservableToBehaviorSubject<T>(observable: Observable<T>, initValue: T): BehaviorSubject<T> {
const subject = new BehaviorSubject(initValue);
observable.subscribe(
(x: T) => {
subject.next(x);
},
(err: any) => {
subject.error(err);
},
() => {
subject.complete();
},
);
return subject;
}