Aaron Balthaser
Aaron Balthaser

Reputation: 2622

Better way to use fork join subsequent to another observable

I have a login process that has fairly complicated login variations and has to be scalable to easily add more in the future. So initially the user is authenticated in the typical manner and a user object is returned. Then I must make additional http calls to get information that will determine the various requirements before the user is granted access to the app. This is done using some of the values returned in the user object. I want to write the code in a way that I can easily add http calls without changing current code so I thought using fork join for the subsequent calls would be good since they can be done in parallel. Below is my working code.

I can easily add new requests to the fork join call and while it doesn't look too bad to me I have been told nested subscriptions is a code smell and typically bad practice. Any ideas on how to do this better would be great.

Thanks.

this.authenticate.login(this.model)
  .subscribe(
    _data => {
      this.subscription = Observable.forkJoin(
        this.devicesHttp.getDevicesByMacAddress(this.macAddress),
        this.teamsService.getTeamsByUserId(_data['userId'])
      );

      this.subscription.subscribe(
        _data => {
          // Check login type and other stuff...
        }
      );
    }
  );

Upvotes: 3

Views: 5998

Answers (3)

dhilt
dhilt

Reputation: 20744

In 2021 this must be written with pipe, stand-alone operators, array in forkJoin and Observer argument in subscribe:

import { concatMap, forkJoin } from 'rxjs';

this.getFirst().pipe(
  concatMap(data =>
    forkJoin([
      this.getSecond(data),
      this.getThird(data)
    ])
  )
).subscribe({
  next: result => ...,
  error: e => ...
});

Upvotes: 2

Robin Dijkhof
Robin Dijkhof

Reputation: 19278

How about this:

this.authenticate.login(this.model)
  .switchMap(data => Observable.forkJoin(
    this.devicesHttp.getDevicesByMacAddress(this.macAddress),
    this.teamsService.getTeamsByUserId(data['userId'])
  ))
  .subscribe(...,...)

Upvotes: 0

martin
martin

Reputation: 96891

For example like this using the concatMap() operator:

this.authenticate.login(this.model)
    .concatMap(_data => Observable.forkJoin(
        this.devicesHttp.getDevicesByMacAddress(this.macAddress),
        this.teamsService.getTeamsByUserId(_data['userId'])
    ))
    .subscribe(_data => {
          // Check login type and other stuff...
    });

The Observables in forkJoin will run in parallel and forkJoin will wait until they both finish.

Also concatMap() waits until the inner Observable completes and then pushes the result further.

Upvotes: 4

Related Questions