Give BehaviorSubject initial value - value being an Observable

Viewed 13925

I know that I cannot give BehaviorSubject an Observable value, but I need a way to solve this issue. On app initialization I am fetching current user (if exists), and I need to give the BehaviorSubject that potential value. So my service code looks like this:

private user = new BehaviorSubject<User>(this.getUser());
public user$ = this.user.asObservable();

getUser(): User {
  // does obviously not work!
  return this.apiService.getUser()
    .map(data => {
      if(data) {
        return data;
      }
      // do something else
    })  
}

So is there some magical rxjs operator to solve this issue, or some other possibility?

Thanks in advance!

3 Answers

I would do it like

private user = new BehaviorSubject<User>(null);
public user$ = this.user.asObservable();

constructor() {
  this.getUser();
}

getUser(): User {
  // does obviously not work!
  return this.apiService.getUser()
    .subscribe(data => {
      if(!!data) {
        this.user.next(data); // <<== added
      }
      // do something else
    })  
}

What if you do something like

private user = new ReplaySubject<User>(1);
public user$ = this.getUser()
    .first()
    .concat(this.user.asObservable());

getUser(): Observable<User> {
    return this.apiService.getUser()
        .map(data => {
            if(data) {
                return data;
            }
            // do something else
        });
}

What this does is just conctenating an observable that returns the first user with the subject so you can push updates. This way you don't need to call .subscribe anywhere

If you don't want to get this.getUser() called for each new subscriber to user Subject, you can always use this.getUser().publish() stream instead, so it gets shared between new subscribers.

Here’s one way of accomplishing this:

private user = new BehaviorSubject(null);
user$ = this.user.switchMap(u => (!!u) 
                                    ? Observable.of(u) 
                                    : this.getUser()
                                          .do(nu =>  if (!!nu) this.user.next(nu))
                                          .switchMap(v => (!v) 
                                                          ? Observable.of(v) 
                                                            : Observable.empty()));

This will rerun the api call so long as user has a falsey value.

Related