blgrnboy
blgrnboy

Reputation: 5167

RxJS Observable - attach Subject consumer on subscribe

I have an Angular service which keeps an private BehaviorSubject so that it can read the value at any given time. It is private so that any component that uses it cannot manipulate it. Instead, a regular Observable is exposed as public. The BehaviorSubject is now a consumer of any data emitted by this observable.

public subheaderData$: Observable<SubheaderData>;
private subheaderDataSubject$: BehaviorSubject<SubheaderData> = new BehaviorSubject<SubheaderData>(null);

constructor(private repository: SubHeaderRepository) {
    this.subheaderData$ = this.load();
    this.subheaderData$.subscribe(this.subheaderDataSubject$);
}

As you can see, I am calling .subscribe from my service, which makes my observable hot immediately. What I would like to accomplish is that a component which injects this service must subscribe to the public Observable, and when that happens, the BehaviorSubject should automatically be added as an observer, even though the component has no knowledge of it (due to it being private.

How can this be accomplished?

Upvotes: 0

Views: 308

Answers (2)

martin
martin

Reputation: 96969

If I'm not missing anything critical I think you should be able to accomplish what you want only by using multicast even though this will be a little unusual use-case.

subheaderDataPublic$ = this.subheaderData$.pipe(
  multicast(this.subheaderDataSubject$, s => s),
);

Then in your component you'll subscribe to subheaderDataPublic$.

Typically, you'd use multicast for example like this:

multicast(new Subject(), s => merge(s, s.pipe(...)))

... but if you pass it this.subheaderDataSubject$ it'll be used as an intermediate Subject. That s => s above is required because without any selector function multicast returns an instance of ConnectableObservable which is probably something you don't need.

EDIT: Maybe a better understandable solution would be using just Observable constructor.

subheaderDataPublic$ = new Observable(observer => {
  const subscriptions = new Subscription();
  subscriptions.add(this.subheaderData$.subscribe(this.subheaderDataSubject$));
  subscriptions.add(this.subheaderDataSubject$.subscribe(observer));

  return () => subscriptions.unsubscribe();
});

Upvotes: 1

Reza
Reza

Reputation: 19933

Do this in your service constructor

this.subheaderData$ = this.subheaderDataSubject$.asObservable();

then subscribe to subheaderData$ whenever needed

and you can this.subheaderDataSubject$.next(someValue) in your service

Upvotes: 1

Related Questions