SKL
SKL

Reputation: 1443

Angular 7 - How to call an API one after one

When 1st API loaded, I need to get value and pass it to second API to get details. With my current code variable become undefined. Here is my code:

app.ts

export class DailyEndorsementComponent implements OnInit {

  public selectedShop: string;
  shop: string[];
  shopData: ShopData;


  constructor(private endorsementService: EndorsementService) {}

  ngOnInit() {
    this.getDates();
    this.loadShopList();
  }

  setPayload() {
    return {
      'startDate': this.fromDate,
      'endDate': this.toDate,
      'settlementBank': this.selectedShop,
    }
  }

  getDates(range: any) {
    this.fromDate = this.datePipe.transform(range.fromDate, 'yyyy-MM-dd');
    this.toDate = this.datePipe.transform(range.toDate, 'yyyy-MM-dd');
    this.loadMerchantDailyEndorsement();
  }

  loadShopList() {
    this.endorsementService.shopList()
      .subscribe(response => {
        this.shop = response;
        this.selectedShop = this.banks[0];
      })
  }

  loadMerchantDailyEndorsement() {
      this.endorsementService.getMerchantEndorsement(this.setPayload())
        .subscribe((response: EndorsementResponseInterface) => {
            this.shopData = response;
          }

        }

app.service.ts

export class EndorsementService extends RestService {

  private BASE_URL_MERCHANT: string = '/settlement/merchant/settlement';
  private BASE_URL_CUSTOMER: string = '/settlement/customer/settlement';

  private headers = new HttpHeaders({
    'Content-Type': 'application/json',
    'Authorization': localStorage.getItem('token')
  });

  constructor(protected httpClient: HttpClient,
    protected injector: Injector,
    protected snackBar: MatSnackBar) {
    super(injector);
  }

  getMerchantEndorsement(body: any): Observable < EndorsementResponseInterface > {
    return this.post < EndorsementResponseInterface >
      (this.getFullUrl(`${this.BASE_URL_MERCHANT}/daily/get`), body, {
        headers: this.headers
      });
  }

  shopList(): Observable < string[] > {
    return this.get < string[] >
      (this.getFullUrl(`/settlement/settlementbanks`), {
        headers: this.headers
      });
  }

}

I need to get value from loadShopList() then call and pass it to loadMerchantDailyEndorsement(). Please let me know if I missed out anything.

Upvotes: 4

Views: 11689

Answers (3)

Nimish
Nimish

Reputation: 1066

You can do this using the mergeMap operator of rxjs.

Angular 4.3+ (using HttpClientModule) and RxJS 6+

getMerchantEndorsement(body): Observable<EndorsementResponseInterface> {
    this.http.post(this.getFullUrl(`/settlement/settlementbanks`, {headers})
      .pipe(mergeMap(character => this.http.get(character.shopId)));
 }

For reference, you can view here

Upvotes: 0

Vlad274
Vlad274

Reputation: 6844

There are a few different ways you could accomplish this, but I believe you should leverage Promises.

export class DailyEndorsementComponent implements OnInit {

  public selectedShop: string;
  shop: string[];
  shopData: ShopData;

  constructor(private endorsementService: EndorsementService) {}

  ngOnInit() {
    this.loadShopList().then(() => {
      this.getDates();
    });
  }

  setPayload() {
    return {
      'startDate': this.fromDate,
      'endDate': this.toDate,
      'settlementBank': this.selectedShop,
    }
  }

  getDates(range: any) {
    this.fromDate = this.datePipe.transform(range.fromDate, 'yyyy-MM-dd');
    this.toDate = this.datePipe.transform(range.toDate, 'yyyy-MM-dd');
    this.loadMerchantDailyEndorsement();
  }

  loadShopList() {
    return new Promise((resolve) => {
        this.endorsementService.shopList()
          .subscribe(response => {
            this.shop = response;
            this.selectedShop = this.banks[0];
            resolve();
          });
    });
  }

  loadMerchantDailyEndorsement() {
      this.endorsementService.getMerchantEndorsement(this.setPayload())
        .subscribe((response: EndorsementResponseInterface) => {
            this.shopData = response;
      }
    }


This seems to be what you want - wait until the first request completes before starting the second.


Documentation

Upvotes: 0

Yanis-git
Yanis-git

Reputation: 7875

for that you need to flat your observable of observable.

Goal is to have 1 observable (here this.endorsementService.shopList) which will be mergeMap to another observable (here this.endorsementService.getMerchantEndorsement)

that means anytime shopList observable will emit new data on stream :

  • you will create new observable getMerchantEndorsement base on the current value of shopList
  • transform the actual shopList to getMerchantEndorsement stream.

i have create dummy demo to ilustrate :

// Simple observable to emulate selected shop from list.
const shopDetail$ = of({
  shop: {
    id: 1,
    name: 'My little poney Inc'
  }
}).pipe(delay(100)); // Delay is added to emulate api call delay. is optional

// Factory for remote data : simple function which emulate http request.
// Base on current id parameter, will return observable of marchandize detail.
const getMarchandizeDetail$ = (id: number) => {
  const dummyDb = { 
    '1': {marchandize : ['poney 1', 'poney 2', 'poney 3']},
    '2': {marchandize : ['element 1', 'element 2', 'element 3']},
  };

  return of(dummyDb[id]);
};

// When current shop change...
shopDetail$.pipe(mergeMap(
  info => {
    // We subscribe to http call : getMarchandizeDetail base on the current shop id.
    return getMarchandizeDetail$(info.shop.id)
  }
)).subscribe(console.log);

live demo

Upvotes: 4

Related Questions