1
votes

I have properties

currentApplication: IApplicationModel;
logos: IImagesModel[];
backgrounds: IImagesModel[];

And I have three observables like this:

  loadApplication(): Observable<IApplicationModel> {
    return this.applicationService.getById(this.applicationId);
  }
  loadApplicationLogos(): Observable<IImagesModel[]> {
    return this.applicationService.getApplicationFiles(this.applicationId, "logo");
  }
  loadApplicationOldBackgrounds(): Observable<IImagesModel[]> {
    return this.applicationService.getApplicationFiles(this.applicationId, "background");
  }

and they do not depend on each other. I want to have ONE subscription, for example with mergeMap(), but I want also to assign the result of each observable.

this.loadApplication()
      .pipe(
        mergeMap(application => this.loadApplicationLogos()),
        mergeMap(application => this.loadApplicationOldBackgrounds()),
        
      )
      .subscribe(res => {
        
      })

How I can assign applications and logos to currentApplication and logos ? Should I use tap() before every mergeMap() or is there a better way with something different from mergeMap?

4

4 Answers

3
votes

You could use a combineLatest to make all your calls at the same time and merge the results at the end:

    combineLatest([
        this.loadApplication(),
        this.loadApplicationLogos(),
        this.loadApplicationOldBackgrounds()
    ]).pipe(
        map(([currentApplication, logos, backgrounds]) => {
            return {
                currentApplication,
                logos,
                backgrounds
            };
        })
    ).subscribe(res => console.log(res));

It will emit when all observables have emit at least once.

2
votes

The perfect solution for you is proablt the combineLatest operator

combineLatest([
  loadApplication(),
  loadApplicationLogos(),
  loadApplicationOldBackgrounds(),
]).subscribe(([res1,res2,res3]) => {...})

The thing that will happen is once all three of your observables return something, you will go inside the subscribe and will recieve all data in an array, after that you can handle the data in whatever way you like it.

0
votes

If you need to load all three in parallel, you can use combineLatest as others have mentioned. If you need to load the application first, you can handle it using something like this:

this.loadApplication().pipe(
    switchMap((application) => {
        return combineLatest(
            this.loadApplicationLogos(application),
            this.loadApplicationOldBackgrounds(application)
        ).pipe(([logos, backgrounds]) => {
            // create an updated application object with logos and backgrounds...
            return {...application, appLogs: logos, appBackgrounds: backgrounds};
        });
    })
);

Here's a tool that I found very helpful when learning RxJS: http://reactivex.io/rxjs/manual/overview.html#choose-an-operator

If you have complicated state management requirements and you're using a lot of RxJS, I recommend looking at NgRedux:

https://ngrx.io/docs

-1
votes

Frankly speaking, all depends on your expecations. If you use combineLatest operator, that stream produces a new value every time the some of input streams produces value. What's more, combineLatest runs observables in sequence

Probably, you want to look at forkJoin operator which runs observables in parallel. It waits on all observables have produces their first values and complete itself.

forkJoin([loadApplication(),loadApplicationLogos(), loadApplicationOldBackgrounds()]).subscribe(([res1,res2,res3]) => {...})