Jake12342134
Jake12342134

Reputation: 1769

Unsure where to put subscription for 3 observables chained with switchMap

this._authService.loggedInUser$.pipe(switchMap((loggedInUser: LoggedInUser) => {
      return this._userSerialService.getUserSerial().pipe(switchMap(serial => {
          return this._usersService.getCurrentUser().pipe(switchMap(currentUser => [loggedInUser, currentUser, serial]));
        }),
      );
    })).subscribe(([loggedInUser, currentUser, serial]) => {

    });

The above code attempts to chain 3 observables together and map their results to an array using switchMaps. I need the result values for all three observables in my final subscription. However when I attempt to subscribe in the way shown above I'm given a compiler error that says `Type 'LoggedInUser' must have a 'Symbol.iterator' method that returns an iterator.

If I do subscribe(res => {}, then res ends up being only the value of loggedInUser, not all three values.

What do I need to change in my code to make sure that I have access to all three values in my subscribe?

Upvotes: 1

Views: 396

Answers (2)

BizzyBob
BizzyBob

Reputation: 14740

It does not look like switchMap is what you need. switchMap is used to "switch" a source observable under the hood so that a new observable can emit into the stream. It handles unsubscribing from the prior source and subscribing to the new one.

In your case, you can simply use combineLatest. This will emit an array of all 3 values once all of the source observables have emitted a value and it will continue to emit whenever any of them receive a new value.

authUser$ = this._authService.loggedInUser$;
serial$   = this._userSerialService.getUserSerial();
user$     = this._usersService.getCurrentUser();

data$ = combineLatest([authUser$, serial$, user$]);


data$.subscribe(([loggedInUser, serial, currentUser]) => {
    ...
});

It can be handy to map the values to an object, so they are easy to retrieve in your template like:

data$ = combineLatest([authUser$, serial$, user$]).pipe(
    map(([authUser, serial, user]) => ({authUser, serial, user}))
);

It's also handy if you leverage the async pipe in your template rather than subscribing in your component.

<div *ngIf="data$ | async as data">
    <ul>
        <li>Current User: {{ data.user }}</li>
        <li>Logged in User: {{ data.authUser }}</li>
        <li>User Serial: {{ data.serial }}</li>
    </ul>
</div>

Upvotes: 1

Reqven
Reqven

Reputation: 1778

switchMap operator takes a function which returns an Observable, then subscribe to it.
The problem here is that your last switchMap gets an array instead of an Observable.
You can use map instead to transform the data.

this._authService.loggedInUser$.pipe(
  switchMap(loggedInUser => this._userSerialService.getUserSerial().pipe(
    switchMap(serial => this._usersService.getCurrentUser().pipe(
      map(currentUser => [loggedInUser, currentUser, serial]))
    )
  ))
).subscribe(([loggedInUser, currentUser, serial]) => {
  ...
});

Upvotes: 0

Related Questions