Explosion Pills Explosion Pills - 1 month ago 7
TypeScript Question

Subscribing to a nested Observable

I have an app that makes one http request to get a list of items and then makes an http request for each item in the list to get more detailed information about each item. Effectively:

class ItemsService {
fetchItems() {
return this.http.get(url)
.map(res => res.json())
.map(items => items.map(this.fetchItem(item)));
}

fetchItem(item: Item) {
this.http.get(`${url}/${item.id}`)
.map(res => res.json());
}
}


Then I'll do something like
itemsService.fetchItems().subscribe(items => console.log(items))
but what ends up happening is I get an array of observables (each response from
fetchItem
). I need to subscribe to each of the internal observables as well so that the
fetchItem
request actually gets triggered.

I've also tried using
flatMap
instead of map but it seems to have the same result in this case. Is there any way for the nested observable to be subscribed to?

Answer

I'd do it like the following:

function mockRequest() {
    return Observable.of('[{"id": 1}, {"id": 2}, {"id": 3}]');
}
function otherMockRequest(id) {
    return Observable.of(`{"id":${id}, "desc": "description ${id}"}`);
}

class ItemsService {
    fetchItems() {
        return mockRequest()
            .map(res => JSON.parse(res))
            .concatAll()
            .mergeMap(item => this.fetchItem(item));
    }

    fetchItem(item: Item) {
        return otherMockRequest(item.id)
            .map(res => JSON.parse(res));
    }
}

let service = new ItemsService();
service.fetchItems().subscribe(val => console.log(val));

See live demo: http://plnkr.co/edit/LPXfqxVsI6Ja2J7RpDYl?p=preview

I'm using a trick with .concatAll() to convert an array of Objects such as [{"id": 1}, {"id": 2}, {"id": 3}] into separate values emitted one by one {"id": 1}, {"id": 2} and {"id": 3} (as of now it's an undocumented feature). Then I use mergeMap() to fetch their content in a separate request and merge it's result into the operator chain.

This plnkr example prints to console:

{ id: 1, desc: 'description 1' }
{ id: 2, desc: 'description 2' }
{ id: 3, desc: 'description 3' }
Comments