Zulukas
Zulukas

Reputation: 1290

Angular waiting for multiple observables to complete

I'm new to Angular, let alone reactive programming and I'm having a hard time wrapping my head around the libraries and understanding how everything is supposed to work together.

There are already multiple questions on Stack Overflow concerning this, but none of the ones I see address the situation I'm dealing with here.

I have two Observables object lists. var obsrv1 = Observable<Object1[]>, var obsrv2 = Observable<Object2[]>.

Let's say I have all the underlying logic for API calls and stuff, and normally, when I do something like obsrv1.subscribe(results => this.objectArray = results), it's going to do it's asynchronous thing and ultimately get me my data.

Now, I have an issue with my two observables, and that is that one of them is reliant upon the other list. When the two lists of data complete, I need to do an action to join them together into another kind of object.

One solution to this is to just do something like this:

obsrv1.subscribe(
  obsrv1Results => {
  this.object1Array = obsrv1Results
  },
  err => {},
  () => {
    obsrv2.subscribe(
      obsrv2Results => {
        this.object2Array = obsrv2Results
      },
      err => {},
      () => onDataLoadComplete();
    );
  }
);

This works, but it feels very hacky. I've gathered that there is a much more elegant way to do this, and it sounds like people suggest doing something with forkJoin, but I have no idea how to get it to work. It sounds like they suggest doing, forkJoin([obsrv1, obsrv2]).subscribe(...), but doing this with my code yields no results and the subscribe callback never gets called. Some folks say to do, forkJoin([obsrv1.first(), obsrv2.first()]), but doing that doesn't work either and the only results I get are literally just , when I do a console.log.

For what it's worth, in my application I am using ngrx/store and ngrx/effects. The call to retrieve my data looks like this:

this.store.select(state => state.myDataContainer.dataList) which returns a Store<MyDataType[]>. From what I have gathered, Store<T> objects must be observables of some form because you can subscribe to them.

How can I go about retrieving both my sets of data asynchronously and have a callback fire when both the sets of data are complete?

Upvotes: 1

Views: 1289

Answers (1)

Robbert Kooiman
Robbert Kooiman

Reputation: 157

It sounds like you should use the .pipe(flatMap()) operator. You can use that to use the result of one Observable and return another Observable, which is what you're describing you want to do.

The ReactiveX.io website is pretty good at visualising and explaining these things.

Here's an example that works out of the box:

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { flatMap } from 'rxjs/operators';

//emit 1
const source = Observable.of(1);
//do something with value
const example = source.pipe(flatMap(value => {return Observable.of(value + 10)}));
//output: 11,12,13,14,15
const subscribe = example.subscribe(val => console.log(val));

And here's what your code could look like implementing this:

obsrv1.pipe(
  flatMap(obsrv1Results => {
    this.object1Array = obsrv1Results;
    return obsrv2;
  })
).subscribe(obsrv2Results => {
  this.object2Array = obsrv2Results;
  onDataLoadComplete();
});

Don't forget to import flatMap if you need it:

import { flatMap } from "rxjs/operators";

Good luck!

Upvotes: 0

Related Questions