Jeremy Thomas
Jeremy Thomas

Reputation: 6684

Chaining subscriptions in RxJS

I have a function in my service as:

newGetClient(client_id, token):Observable<Response> {
  let headers = new Headers();
  headers.append("authentication", token );
  let options = new RequestOptions({ headers: headers });

  let final_url = `${this.baseUrl}/${client_id}?model=client`

  return this.http.get(final_url, options)
    .map(this.extractData)
    .catch(this.handleError)
}

which I call in my controller as:

fetchClients() {
  this.clientService.newGetClient(this.client_ids[0], this.auth_token).subscribe( data => {
    this.c1 = this.parseClient(data)
    this.clientService.newGetClient(this.client_ids[1], this.auth_token).subscribe( data => {
      this.c2 = this.parseClient(data)
      this.generateKeys()
    })
  })
}

generateKeys() {
  this.keys = _.union(Object.keys(this.c1), Object.keys(this.c2))
  this.loaded = true
}

but I'm making the call to fetchClients() with 2 different client_ids and I need to make a seperate call to generateKeys() once both calls to fetch have been completed.

I feel as though nesting the calls to newGetClient() is incorrect so I'm wondering how to chain them so that I can call generateKeys() once both subscriptions are complete.

Upvotes: 1

Views: 396

Answers (2)

martin
martin

Reputation: 96889

Since these two calls are not dependent on each other you can use forkJoin():

const o1 = this.clientService.newGetClient(this.client_ids[0], this.auth_token);
const o2 = this.clientService.newGetClient(this.client_ids[1], this.auth_token);

Observable.forkJoin(o1, o2).subscribe(([result1, result2]) => {
  this.c1 = this.parseClient(result1);
  this.c2 = this.parseClient(result2);
  this.generateKeys();
});

If you want to be able to assign c1 and c2 as they arrive without waiting for both of the Observables to complete you could chain o1 and o2 with do():

const o1 = this.clientService.newGetClient(this.client_ids[0], this.auth_token).do(res => this.c = res);

Upvotes: 3

dashton
dashton

Reputation: 2704

You could use zip to combine your two observables - it will emit when both observables have emitted.

Something like this (note: it's not tested, but you should get the idea):

fetchClients() {
    rx.observable.zip(
        this.clientService.newGetClient(this.client_ids[0], this.auth_token).map(this.parseClient),
        this.clientService.newGetClient(this.client_ids[1], this.auth_token).map(this.parseClient)
    )
    .map(arrClients => _.union(Object.keys(arrClients[0]), Object.keys(arrClients[1])))
    .subscribe( clientUnion => {
        this.keys = clientUnion;
        this.loaded = true
      });
}

Upvotes: 1

Related Questions