0

I have following setup:

    let result = service.getResults();

    result.data.forEach((row:any) => {
          this.myService
            .getObject(row.id)
            .subscribe((object:any) => {
              //...
            })
        );
      }

I want do do something, after all the subscriptions of getObject(row.id) have finished. I know there's the add() function but it will do this for every Subscription. Coming from Promises I would have stored every Promise and then in an array and just called Promise.all().

user5417542
  • 3,146
  • 6
  • 29
  • 50
  • An observable is never finished. What you can do, will be to get the next value of each observable. But if you are sur that it's an ponctual request, you can convert your Observable as a promise `.toPromise()` and then you know how to deal with it – Wandrille Mar 13 '19 at 11:55
  • @Wandrille _An observable is never finished_ if you consider finished to be _completed_, then your statement is wrong. – Jota.Toledo Mar 13 '19 at 12:00
  • @Wandrille An observable is finished with `complete()` method of the observer. For example, HTTP requests returns observable and the observable is **finished** once its subscription is fired. – Harun Yilmaz Mar 13 '19 at 12:05
  • @Jota.Toledo you're right – Wandrille Mar 13 '19 at 12:05
  • @Harun Yılmaz Thanks for the info. – Wandrille Mar 13 '19 at 12:08

2 Answers2

4

I want do do something, after all the subscriptions of getObject(row.id) have finished.

Better to use forkJoin for your example. From official docs:

forkJoin will wait for all passed Observables to complete and then it will emit an array with last values from corresponding Observables.

Try to do it in this way:

import { forkJoin } from 'rxjs';

const rowObjects$ = result.data.map(rd => this.myService.getObject(rd.id));

forkJoin(rowObjects$)
  .subscribe((object:any) => {
    //...
  })
Vadi
  • 3,279
  • 2
  • 13
  • 30
-1

You can use combineLatest to combine all the observables and wait until every observable fires at least once.

import {combineLatest} from 'rxjs';
...



let result = service.getResults();

const observablesToCombine = [];

result.data.forEach((row:any) => {
      observablesToCombine.push(this.myService.getObject(row.id));
})

combineLatest(observablesToCombine).subscribe((object: Array<any>) => {
     //...
})
Harun Yilmaz
  • 8,281
  • 3
  • 24
  • 35
  • `combineLatest` will emit each time any of the inner observables emits. The OP wants this to only happen whne all inner observables are complete. – xandermonkey Mar 13 '19 at 13:01
  • @xandermonkey Not each time always but each time after every one of them is fired at least once. And I can't see where OP stated he wants to fire only once. – Harun Yilmaz Mar 13 '19 at 13:06
  • "after all the subscriptions of getObject(row.id) have finished". I downvoted because it's a wrong answer – xandermonkey Mar 13 '19 at 13:38
  • @xandermonkey `combineLatest` will only fire after every inner observable fires **at least once** as well as `forkJoin`. The only difference between two of them is that the `forkJoin` performs parallel execution and finishes (completes) while `combineLatest` performs serial execution (using `concat` inside) and does not finish (complete). So, `combineLatest` should work well for OP as well. And also see: https://stackoverflow.com/a/41797505/1331040 – Harun Yilmaz Mar 13 '19 at 13:43