0

This is what I have:

  ngOnInit() {
    this._addServ.getDefaultAddress().subscribe((res)=>{
      if(res.status){
        //I need these next two functions to finish their async API requests 
        //before selectNormalDelivery is called
        this.selectShippingAddress();
        this.selectBillingAddress();
        this.selectNormalDelivery();
      }
    })
  }

I need selectShippingAddress and selectBillingAddress to finish their calls, and then for selectNormalDelivery to be called. How can I accomplish this? I don't want to convert them into promises as they're called other times without needing to be chained. Is this something involving .then?

This is the code for the functions:

  selectShippingAddress(){
    this.addressService.setShippingAddresses(this.cartService.shippingAddress.address_id).subscribe((res) => {
      console.log('Set shipping address!')
      console.log(res);
    }, err => {
      console.log('Failed to set shipping address')
      console.log(err);
    })
  }

  selectBillingAddress(){
    this.addressService.setPaymentAddresses(this.cartService.billingAddress.address_id).subscribe((res) => {
      console.log('Set billing address!')
      console.log(res);
    }, err => {
      console.log('Failed to set billing address')
      console.log(err);
    })
  }

If I try a .then, I get the error Property 'then' does not exist on type 'void'., which makes sense as I'm not trying to return anything, I just need them to complete their calls for the API's sake.

Suggestions?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
fourOhFour
  • 77
  • 9
  • Then you need to change those functions to return something: a promise, if you want to use `.then`; or an observable. Or they could accept a callback, but adding in another async paradigm probably isn't a good idea. – jonrsharpe May 29 '20 at 16:49
  • Hmmm, I'm not very familiar with creating and subscribing to custom observables. Could I also try using the approach of same component Event Emitters? And for the functions to listen to each other? – fourOhFour May 29 '20 at 17:35
  • I'd recommend reading up on that, then, it's an important part of the way Angular handles most async things. – jonrsharpe May 29 '20 at 17:37
  • This may help you. https://stackoverflow.com/questions/49596641/is-it-a-good-practice-using-observable-with-async-await – Deeksha Pandit May 29 '20 at 17:43
  • check my solution below. – Aakash Garg May 29 '20 at 17:48

2 Answers2

1

If I understand correctly, you need to listen to one observable (from getDefaultAddress()), then process two other observables (this.addressService.setShippingAddresses() and this.addressService.setPaymentAddresses()) and after that call function selectNormalDelivery().

You could do so by using RxJS switchMap, catchError, tap operators and forkJoin(). Try the following

import { forkJoin, EMPTY } from 'rxjs';
import { tap, catchError, switchMap } from 'rxjs/operators';

ngOnInit() {
  this._addServ.getDefaultAddress().pipe(
    switchMap((res) => {        // <-- map the observable from `getDefaultAddress()` to another observable
      if(res.status) {
        return forkJoin([       // <-- `forkJoin` emits only after the observables complete
          this.selectShippingAddress(), this.selectBillingAddress()
        ])
      }
    })
  ).subscribe(response => {
    this.selectNormalDelivery()
  })
}

selectShippingAddress() {
  return this.addressService.setShippingAddresses(this.cartService.shippingAddress.address_id).pipe(
    tap((res) => {            // <-- `tap` doesn't alter the response
      console.log('Set shipping address!')
      console.log(res);
    }),
    catchError((err) => {     // <-- `catchError` must return an observable
      console.log('Failed to set shipping address')
      console.log(err);
      return EMPTY;
    }))
}


selectShippingAddress() {
  return this.addressService.setPaymentAddresses(this.cartService.shippingAddress.address_id).pipe(
    tap((res) => {
      console.log('Set billing address!')
      console.log(res);
    }),
    catchError((err) => {
      console.log('Failed to set billing address')
      console.log(err);
      return EMPTY;
    }))
}
ruth
  • 29,535
  • 4
  • 30
  • 57
  • I like this! Not only did you give me a solution, but also some concepts (Tap, switchMap, etc) to further research. Thanks! – fourOhFour May 29 '20 at 18:21
0
ngOnInit() {
    this._addServ.getDefaultAddress().subscribe((res)=>{
      if(res.status){
        //I need these next two functions to finish their async API requests 
        //before selectNormalDelivery is called
        forkJoin([this.selectShippingAddress(),this.selectBillingAddress()].subscribe(() => {

            this.selectNormalDelivery();
        });
      }
    })
  }

 selectShippingAddress(){
    return this.addressService.setShippingAddresses(this.cartService.shippingAddress.address_id).pipe(map((res) => {
      console.log('Set shipping address!')
      console.log(res);
    }, err => {
      console.log('Failed to set shipping address')
      console.log(err);
    }));
  }

  selectBillingAddress(){
    return this.addressService.setPaymentAddresses(this.cartService.billingAddress.address_id).pipe(map((res) => {
      console.log('Set billing address!')
      console.log(res);
    }, err => {
      console.log('Failed to set billing address')
      console.log(err);
    }));
  }
Aakash Garg
  • 10,649
  • 2
  • 7
  • 25