Search code examples
angularrxjs6

Chaining observables and feeding result into next


I want to use the result of one subscription to feed another. What is the best way of doing this in Angular 7? Currently, my subscription works intermittently (data is not returned to the user).

this.userService.getNumberOfUsers().subscribe(data => {
  if (data) {
    this.noOfUsers = data.data['counter'];
    this.tempRanking = this.referralService.getWaitlist().subscribe(waitlistResult => {
      if (waitlistResult && this.userData.referralId) {
        return this.referralService.calculateRanking(this.userData.referralId, waitlistResult).then((result: number) => {
          if (result) {
            if (result > this.noOfUsers) {
              this.ranking = this.noOfUsers;
            } else {
              this.ranking = result;
            }
          }
        });
      }
    });
  }
});

Solution

  • this.referralService.getWaitlist().pipe(
        filter(waitlistResult  => waitlistResult != null),
        switchMap(waitlistResult  => combineLatest( this.referralService.calculateRanking(this.userData.referralId, waitlistResult ), this.userService.getNumberOfUsers())),
        filter(combined => combined[0] != null && combined[1] != null)
    ).subscribe(combined =>{
        if (combined[0] > combined[1]) {
            this.ranking = combined[1].data['counter'];
        } else {
            this.ranking = combined[0];
        }
    })
    

    An even better way would be to subscribe to the result in your template:

    public ranking$: Observable<number>;
    

    ...

    this.ranking$ = this.referralService.getWaitlist().pipe(
        filter(waitlistResult  => waitlistResult != null),
        switchMap(waitlistResult  => combineLatest( this.referralService.calculateRanking(this.userData.referralId, waitlistResult ), this.userService.getNumberOfUsers())),
        filter(combined => combined[0] != null && combined[1] != null),
        map(combined =>{
            if (combined[0] > combined[1]) {
                return combined[1].data['counter'];
            } else {
                return combined[0];
            }
        })
    );
    

    ...

    <div>{{ranking$ | async}}</div>
    

    Edit I see that this.referralService.calculateRanking returns a promise, you might want to convert that to an observable in that function or use 'from'

    import { from } from 'rxjs';
    from(this.referralService.calculateRanking(...))
    

    Edit 2

    public numberOfUsers$: Observable<number>;
    public ranking$: Observable<number>;
    

    ...

    this.numberOfUsers$ = this.userService.getNumberOfUsers();
    this.ranking$ = this.referralService.getWaitlist().pipe(
        filter(waitlistResult  => waitlistResult != null),
        switchMap(waitlistResult  => combineLatest( from(this.referralService.calculateRanking(this.userData.referralId, waitlistResult )), this.numberOfUsers$)),
        filter(combined => combined[0] != null && combined[1] != null),
        map(combined =>{
            if (combined[0] > combined[1]) {
                return combined[1].data['counter'];
            } else {
                return combined[0];
            }
        })
    );
    

    ...

    <p style="font-size: 1.25em" *ngIf="ranking">You are in position <strong> {{ranking$ | async}}</strong> of <strong>{{ numberOfUsers$ | async }}</strong> on the waitlist.</p>