Reputation: 17752
I have a service, MyService
, which has a method getList()
which returns an Observable of an array of Items, something like
getList(): Observable<Item[]>
Once the list is retrieved, then each Item needs to go through a second method of MyService
, fillItem(Item)
. This method issues a request to some back end which returns a Promise, something like:
fillItem(item: Item) {
BackEnd.retrieveDetails(item.id)
.then(data => item.data = data);
}
What I need is to combine the above two methods so that MyService is able to return an Observable which emits the list of Items once all of them have been filled with their data (i.e. once all Promises have been resolved).
What I have tried so far is something along these lines
fillAll(items: Item[]) {
const promises = [];
for (let i = 0; i < items.length; i++) {
const item = items[i];
promises.push(this.fillItem(item));
}
const subject = new Subject<Item[]>();
Promise.all(promises).then(res => {
subject.next(items);
},
err => {
subject.error(err);
});
return subject.asObservable();
}
getListWithFilledItems() {
return this.getList()
.map(items => this.fillAll(items))
}
Unfortunately, if I do so, the method getListWithFilledItems()
returns an Observable<Observable<Item[]>>
and not, as I hoped, an Observable<Item[]>
.
Any suggestion on how to change the code so that the method getListWithFilledItems()
returns an Observable<Item[]>
would be appreciated.
Upvotes: 0
Views: 1133
Reputation: 96891
I think instead of .map(items => this.fillAll(items))
you can use just mergeMap()
:
.mergeMap(items => this.fillAll(items))
This will subscribe to the Observable returned from fillAll()
and reemit its value when it's ready.
Btw, be aware that you're not calling complete()
on the internal subject
so the Observable chain isn't disposed properly (however it might not event matter in your use-case).
Upvotes: 1