rxjs with multiple forkjoin when doing http requests
Asked Answered
C

1

1

I am doing some http requests and use rxjs for successfull notification of the result:

  getReportings(departmentId: number): Observable<any> {
        return Observable.forkJoin(
            this.http.get('/api/members/' + departmentId).map(res => res.json()),
            this.http.get('/api/reports/' + departmentId).map(res => res.json())
        );
    }

When both http requests are done I want inside the getReportings method to iterate the reports array , read some values and for each report make again a new http request with those values.

All in all I have 2 (member/reports) + appr. 4 to 8 (other stuff) requests.

When all appr. 6 to 8 requests are done I want to get ALL data from the previous 6 to 8 requests in the successfull handler.

How can I do this with rxjs?

UPDATE

As user olsn asked for more details and I understand him now whats his concern I put more data here (pseudo code) how the 6 to 8 requests should look like:

getReportings(departmentId: number): Observable<any> {
    return Observable.forkJoin(
        this.http.get('/api/members/' + departmentId).map(res => res.json()),
        this.http.get('/api/reports/' + departmentId).map(res => res.json())
    ).switchMap((result: [any[], any[]]) => {
        let members: any[] = result[0];
        let reports: any[] = result[1];
        let allNewStreams: Observable<any>[] = [
            Observable.of(members),
            Observable.of(reports)
        ]; 

        for(let report of reports)
        {
            allNewStreams.push(
this.http.get(report.url + ?key1=report.name1?).map(res => res.json()));
        }


        return Observable.forkJoin(allNewStreams); // will contain members, reports + 4-6 other results in an array [members[], reports[], ...other stuff]
    });
}
Crowther answered 17/12, 2016 at 23:29 Comment(0)
U
6

You could extend your stream using switchMap, like this:

getReportings(departmentId: number): Observable<any> {
    return Observable.forkJoin(
        this.http.get('/api/members/' + departmentId).map(res => res.json()),
        this.http.get('/api/reports/' + departmentId).map(res => res.json())
    ).switchMap((result: [any[], any[]]) => {
        let members: any[] = result[0];
        let reports: any[] = result[1];
        let allNewStreams: Observable<any>[] = [
            Observable.of(members),
            Observable.of(reports)
        ];
        // do your stuff and push new streams to array...
        if (foo) { // for each additional request
            let reportId: string | number = reports[0].id; // or however you retrieve the reportId
            allNewStreams.push(
                this.http.get('some/api/ + bar)
                    .map(res => res.json())
                    .map(data => ({reportId, data})); // so your final object will look like this: {reportId: "d38f68989af87d987f8", data: {...}}
            );
        }

        return Observable.forkJoin(allNewStreams); // will contain members, reports + 4-6 other results in an array [members[], reports[], ...other stuff]
    });
}

This should do it, it's more like an "old-style-logic-hammer" approach - in case you are looking for it: There might be a more elegant way to solve this by using other operators, but that is hard to say without knowing the full data and all logic.

Urethrectomy answered 17/12, 2016 at 23:50 Comment(6)
Thanks! Would the meaning of the variables really allow a better technical solution? There is no more logic concerning the http requests. The logic starts when tge single client side service call gets all the http request`s data he subscribed to. What "full data" are you missing?Crowther
The question is: How are the other 4-6requests determined, my understanding was, that they are dependant on certain data from the member+reports requests and might or might not be called - this could be based on the numbet of reports...it could be based on some flags within a report ...or...or..ect...depending on that there are different rxjs operators that could be used - in any case the if/else -way should work non the less.Urethrectomy
Just tested the code and it works. But as things go on I realize I still have a problem. all the 4-8 requests 'might' arrive in a random order in the response. I do not want to leave on the rxjs author`s brain ;-) Regarding my pseudo code, is it possible to pass each of the 4-8 requests a report_Id AFTER the http requests have been done? I want to have an association of the return data with each report. Lets say each report of reports has an id and instead of return an array of data for each report.url request I return an object with the report_Id and the returned data :-)Crowther
Sure, just add an additional .map(...) - The order in your subscription should not be random regalrdless of the executiontime since the forkjoin will only propagate data once all the requests have been completed - and their order is the same order of the input-Array.Urethrectomy
I agree that the order of the allNewStreams and its obserable items is the same when I get the successfull response and its arrays BUT in my component.ts I am not aware how the stuff was mapped in my reportingservice.ts therefore I need the references finally :-) Could you show me a bit more please how you would where use the .map() method to map each report.id to the calling 4-8 requests?Crowther
True - I have extended the example in my answer with an additional .map(...)Urethrectomy

© 2022 - 2024 — McMap. All rights reserved.