-1

How do I wait for an API To Complete, and then next conduct next step in Angular with clean code? I do not want to place future steps within the subscribe. Is there a way to make an API complete first?

public overallMasterFunction(){
    executeMemberSetup();
    let price = calculatePriceAPI();  // Wait for this API line to complete, and conduct further steps
    let totalAmount = price * this.quantity;
    console.log('Sales Completed')
}

calculatePriceAPI(){
  this.customerSalesProxy.getPrice().subscribe(res => {
    if (res?.totalPrice) {
      this.totalPrice = res.totalPrice
    }
  });
}
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86

3 Answers3

1

You cannot return a synchronous value from an asynchronous function such as let price = calculatePriceAPI();. It goes against reactive programming. One big reason for this behavior is to help with situations such as

How do I wait for an API To Complete

. The sooner you embrace it, the easier it gets to use it.

That said, one way would be to return an observable from the asynchronous function. But note that you still need to subscribe to it to use the value. Try the following

public overallMasterFunction(){
    executeMemberSetup();
    let totalAmount: any;
    this.calculatePriceAPI().subscribe(
      price => { totalAmount = price * this.quantity; }
    );
    console.log('Sales Completed');
}

calculatePriceAPI(){
  const result = new Subject<any>();

  this.customerSalesProxy.getPrice().subscribe(res => {
    if (res.totalPrice) {
      this.totalPrice = res.totalPrice;
      result.next(res.totalPrice);
    }
  });

  return result.asObservable();
}

BTW there are number of abnormalities in the code.

  1. You are assigning the value to member variable this.totalPrice. Yet not using it when needed.
  2. Assigning a variable to a function such as let price = calculatePriceAPI(); points to the function. Because here the output is asynchronous and you cannot return a synchronous data out of it. See here for info on asynchronous requests.
  3. Member functions should be referenced by this keyword. It is missing in let price = calculatePriceAPI();.
  4. As pointed out by @amakhrov in comments, in this specific case the calculatePriceAPI() function isn't doing a lot. The primary subscription could be done directly in the parent function.
public overallMasterFunction(): Observable<any> {
    const result = new Subject<any>();
    let totalAmount: any;

    executeMemberSetup();
    this.customerSalesProxy.getPrice().subscribe(res => {
      if (res.totalPrice) {
        this.totalPrice = res.totalPrice;
        totalAmount = res.totalPrice * this.quantity;
        result.next(totalAmount);
      }
    });
    console.log('Sales Completed');

    return result.asObservable();
}
ruth
  • 29,535
  • 4
  • 30
  • 57
  • 1
    Note that `calculatePriceAPI` here does pretty much nothing. Inside `overallMasterFunction` you can subscribe directly to the result of `this.customerSalesProxy.getPrice()` – amakhrov Apr 03 '20 at 06:12
0

You can use async await.

async ngOnInit() {
    await new Promise(resolve => setTimeout(resolve, 5000));
    console.log('Done!');
}

Without async await, the console log would show immediately. Using async await code waits for the completion of async code.

Carsten
  • 4,005
  • 21
  • 28
0

What you could to is, instead of working with Observables here, work with Promises as they can be combined with async/await which allows a synchronous code flow.

public async overallMasterFunction(){
    executeMemberSetup();
    let price = await calculatePriceAPI();  // Wait for this API line to complete, and conduct further steps
    let totalAmount = price * this.quantity;
    console.log('Sales Completed')
}

calculatePriceAPI(): Promise<any> {
  return this.customerSalesProxy.getPrice().toPromise();
}

Pay attention to the async in the method signature which signals that this function does do asynchronous communication and allows to use the await keyword within. Await will make sure the Promise is resolved before going to the next line. This should feel very natural again as it is basically synchronous code now.

However, in most cases you should be fine without async/await and make full usage of Obserables and asynchronous communication in general.

Find an example below:

public overallMasterFunction(){
    executeMemberSetup();
    let price = calculatePriceAPI().subscribe(price => {
        let totalAmount = price * this.quantity;
        console.log('Sales Completed')
    });
}

calculatePriceAPI(): Observable<any> {
  this.customerSalesProxy.getPrice();
}

From your API, simply return the Observable so that your code can react upon it with it sown subscribe. Then, within that subscribe you can use the price and log something to console once everything is finished.

gerstams
  • 415
  • 2
  • 12