2

I have a function which makes two http calls, the input of second http depends first http response and I need the two results to be returned at the same time. I have the below code which throws the error

SomeMethod(): Observable<any> {
    let firstResult;
    let secondResult;

    firstResult = http.get('////').map(data => {
        console.log('first response')
     secondResult = http.get('//// + {data.UserId}').map(response => {

        console.log('second response')
     })
    })

    return forkJoin([firstResult, secondResult]);
}

CallingMethod() {
    this.SomeMethod.subscribe(([firstResult, secondResult]) =>{
     /// Some logic
    })}

Getting error as undefined. Expected a observable, promise or array. After debugging got to know that first console output is printing, the second http call is never made and response is never seen.

How to return two nested calls responses together using forkJoin or any other mechanism?

Mel
  • 5,837
  • 10
  • 37
  • 42
thecrusader
  • 301
  • 6
  • 18

4 Answers4

6

Here is a StackBlitz of how to do this using concatMap. concatMap will execute sequentially, where as forkJoin will execute in parallel.

What you need to know

    const requests = [
      this.http.get('https://jsonplaceholder.typicode.com/todos/1'),
      this.http.get('https://jsonplaceholder.typicode.com/todos/2'),
      this.http.get('https://jsonplaceholder.typicode.com/todos/3'),
      this.http.get('https://jsonplaceholder.typicode.com/todos/4'),
      this.http.get('https://jsonplaceholder.typicode.com/todos/5'),
      this.http.get('https://jsonplaceholder.typicode.com/todos/6')
    ];


    from(requests).pipe(    
      concatMap((request) => request.pipe(delay(2200)))
    ).subscribe((res) => {
      this.results$.next(this.results$.getValue().concat(res))
    })
  1. We create an array of requests (which are observables).
  2. Use the from operator to take your array and emit each array item
  3. Flatten those emissions with concatMap

I added a delay here as well to simulate slow loading.

Ian Jamieson
  • 4,376
  • 2
  • 35
  • 55
  • Do you have any suggestion how to modify your code, to get a result _once_ (like forkJoin does) after all sequential(!) requests got completed? – juli May 07 '20 at 11:36
  • Arg, could not edit anymore. If anyone else is searching for this behaviour, it´s just like this: `from(requests).pipe( concatMap((request) => request.pipe(delay(2200))), reduce((acc, cur) => [...acc, cur], []), ).subscribe((res) => { console.log('res', res); })` – juli May 07 '20 at 14:28
  • @juli I think `toArray()` would also work instead of `reduce` – Lossan Aug 16 '21 at 15:09
3

Use Async & await to control multiple http requests.

async SomeMethod(): Promise <any> {

    let firstResult;
    let secondResult;
    firstResult = await http.get('////').toPromise();
    secondResult = await http.get('//// + {res1.UserId}').toPromise();

    return forkJoin(firstResult, secondResult);
}

 CallingMethod() {
    this.SomeMethod().then(result => {
       /// Some logic
    });
 }
Mjstk
  • 508
  • 4
  • 9
1

The following code should work:

SomeMethod(): Observable < any > {
  let firstResult;
  let secondResult;

  return http.get('////').pipe(
    switchMap(res1 => http.get('//// + {res1.UserId}').pipe(
      map(res2 => [res1, res2])
    ))
  );
}

CallingMethod() {
  this.SomeMethod().subscribe(([firstResult, secondResult]) => {
    /// Some logic
  })
}
Xinan
  • 3,002
  • 1
  • 16
  • 18
  • i am getting the following error after using the code **the this context of type void is not assignable to methods this of type observable** even followed the link [rxjs pipe](https://stackoverflow.com/questions/47198706/rxjs-pipe-and-lettable-operator-map-this-context-of-type-void-is-not-assi/47198895) but coudn't solve – thecrusader Sep 25 '18 at 06:54
  • You need to post your full code in order to get it properly debugged. I think it's just some silly tiny mistakes somewhere. – Xinan Sep 25 '18 at 16:53
0

forkJoin takes arguments inline, not as an array (unless that's a change in rxjs between latest and what was bundled in Angular v4)

const req1 = this.http.get('https://jsonplaceholder.typicode.com/todos/1');
const req2 = this.http.get('https://jsonplaceholder.typicode.com/todos/2');

const results = forkJoin(req1, req2)

Output:

[
  {
    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
  },
  {
    "userId": 1,
    "id": 2,
    "title": "quis ut nam facilis et officia qui",
    "completed": false
  }
]

StackBlitz is in v6 but its easy enough to back track if needed.

Phix
  • 9,364
  • 4
  • 35
  • 62