1

I'm trying to call two API, but these are called one after the other, hence i'm wasting time unnecessarily. How to call both at the same and help me save time.

this.data = await this.processService.workflowAPI1('activiti$requisitionandpo', 'COMPLETED').then((d: any) => {
      return d;
    })

this.APIresponse = await this.processService.workflowAPI(selected_actID).then((d: any) => {
      console.log(d)
      this.spinner.hide();
      this.showTable = true;
      return d;
    })

Edit: Thank you for answering my question, I tried all your method, Provided all method works, but i'm facing issues while invoking this.data in each one. is it due to asynchronous problem?

this.data.forEach(element => {
      element['properties'] = element.properties.map;
      columns.forEach(column => {
        if (column.header == 'PO Number') {
          if (column.hasMulValue) {
            column.value_list.forEach(value => {
              var column_value = this.adminService.loadColumnValue(value, element);
              if (column_value != null && column_value != '0') {

                element['po_num'] = column_value;

              }
            })
          }
        }
      })
      // element1.po_num = element1.properties.map.aclrq_poNum
      var x = new Date(element.properties.completionDate);
      var y = new Date("Oct 18, 2020");
      if ((element.taskType == "aclrq:PreparePo") && (x > y)) {
        arraynew.push(element)
      }
    })
vendor.js:69393 ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'forEach' of undefined
TypeError: Cannot read property 'forEach' of undefined
    
BLNT
  • 94
  • 2
  • 8
  • Where are you calling the forEach – MoxxiManagarm Nov 05 '20 at 14:31
  • in a different function, i'm loading two api's in one function and in the same function i'm calling another function which has `forEach` – BLNT Nov 05 '20 at 14:34
  • The function in which you await the responses is async and therefor also returns a promise. You need to await the Promise from the first function (with async-await) before calling the second function (with forEach) or call the second function in then callback of the first function – MoxxiManagarm Nov 05 '20 at 14:42
  • if i bring all things at one function which is async function, facing asynchronous issues. before doing this everything was working fine in my case. i just wanted to call both apis at same time. – BLNT Nov 05 '20 at 14:48

3 Answers3

1

You can use Promise.all()

[this.data, this.APIresponse] = await Promise.all([
  this.processService.workflowAPI1(/**/),
  this.processService.workflowAPI(/**/)
]);
MoxxiManagarm
  • 8,735
  • 3
  • 14
  • 43
1

I assume you're using Angular HttpClient to make the HTTP calls and converting the observables returned by them to promises in the service.

If that's the case, avoid converting them to promises and use the observables directly. You could then use RxJS forkJoin function to trigger multiple requests in parallel. Additionally use could also use RxJS operators like tap and finally to verify the response and hide the spinner.

Try the following

import { forkJoin } from 'rxjs';
import { tap, finally } from 'rxjs/operators';

forkJoin({
  data: this.processService.workflowAPI1('activiti$requisitionandpo', 'COMPLETED'),
  APIresponse: this.processService.workflowAPI(selected_actID).pipe(
    tap(d => console.log(d)),    // <-- `tap` to confirm if the response is emitted
    finally(() => {              // <-- `finally` to hide spinner and show table when the request completes
      this.spinner.hide();
      this.showTable = true;
    })
  )
}).subscribe({
  next: response => {
    this.data = respose.data;
    this.APIresponse = response.APIresponse;
  },
  error: error => {
    // handle error
  }
});

If for any reason you have to use promised to fetch the data, you could convert them to observables using RxJS from function and continue as shown above

import { from, forkJoin } from 'rxjs';
import { tap, finally } from 'rxjs/operators';

forkJoin({
  data: from(this.processService.workflowAPI1('activiti$requisitionandpo', 'COMPLETED')),    // <-- convert promise to observable
  APIresponse: from(this.processService.workflowAPI(selected_actID)).pipe(                   // <-- convert promise to observable
    ...
  )
}).subscribe(...);

Update: this.data is undefined

The variable this.data is assigned asynchronously. So any statements that directly depend on it must be inside the subscription.

import { forkJoin } from 'rxjs';
import { tap, finally } from 'rxjs/operators';

forkJoin({
  ...
}).subscribe({
  next: response => {
    this.APIresponse = response.APIresponse;
    this.data = response.data;
    this.data.forEach(element => {  // <-- this should be inside the subscription
      ...
    });
  },
  error: error => {
    // handle error
  }
});

You could learn more about asynchronous data here.

ruth
  • 29,535
  • 4
  • 30
  • 57
  • i need to call `this.data` outside of it. i'm trying to use it in some other function, hence i declared it as a property – BLNT Nov 05 '20 at 13:56
  • Short answer: you cannot. Please refer the linked answer to understand why you can't do it. You need to either cache the output to an observable in the service and use it in the component or directly subscribe to the source where the output is required. – ruth Nov 05 '20 at 14:01
0

Here rxjs operator forkJoin will come for your help. But first you'll have to convert your promise into observable for that use from rxjs operator. So first import required operators

import {from, forkJoin} from 'rxjs';

Then use the forkJoin operator like this

let req1$ = from(this.processService.workflowAPI1('activiti$requisitionandpo', 'COMPLETED'));
let req2$ = from(this.processService.workflowAPI(selected_actID));
//pass both api calls to the forkJoin operator
forkJoin(req1$, req2$).subscribe(([res1, res2])=>{

//response of first api call
console.log(res1);

//response of second api call
console.log(res2);
});
Obaid
  • 2,563
  • 17
  • 15