2

I use angular 10 in my project. I have two functions initData1 and initData2.

I have two functions:

initData1(){
    //some http client services

    this.dataService.getTitleImageUrl(this.data.titlId, this.data.id )
    .subscribe( resp => {  this.titeImageUrl = encodeURI(resp.results[0]) });

    this.storeService.getContactImageUrl(this.store.titlId, this.store.id )
    .subscribe( resp => {  this.contactImageUrl = encodeURI(resp.results[0]) });
}


initData2(){
   //some http client services

    this.dataService.getTitleImageUrl(this.data.titlId, this.data.id )
    .subscribe( resp => {  this.titeImageUrl = encodeURI(resp.results[0]) });

    this.storeService.getContactImageUrl(this.store.titlId, this.store.id )
    .subscribe( resp => {  this.contactImageUrl = encodeURI(resp.results[0]) });
}

Here how I call functions in my component:

      ngOnInit(): void  {
        initData1();
        initData2();
      }
      

My question is how to execute the initData2 function only after all httpclient services are resolved in the initData1 function?

UPDATE: add examples of http client services

Michael
  • 13,950
  • 57
  • 145
  • 288
  • Are they asynchronoues, i.e. do they return a Promise? Can you pass `initData1` a callback that'll get called at the end? – Kelvin Schoofs Jul 29 '21 at 18:50
  • If the functions are asynchronous, or can be made asynchronous, then you might want to use [Promise.all](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all). – lejlun Jul 29 '21 at 18:55
  • You can simply call the second function `initData2();` inside the response block of first function call. – Tushar Jul 29 '21 at 19:02
  • @KelvinSchoofs, please see the update I added content to the functions – Michael Jul 29 '21 at 19:58

2 Answers2

2

Ideally you'd have to use some of the RxJS functions and operators at your disposal. And when it comes to observables,

  1. It's better to subscribe them where it's response is required
  2. Use as less subscriptions as possible

Given these, I'd make the following changes to your implementation.

initData1(): Observable<any> {  // <-- return observable here
  // use `forkJoin` function to trigger multiple observables in parallel
  return forkJoin({
    title: this.dataService.getTitleImageUrl(this.data.titlId, this.data.id),
    contact: this.dataService.getTitleImageUrl(this.data.titlId, this.data.id)
  }).pipe(
    // use `tap` operator to perform side-effects
    tap(imageUrls => {
      this.titleImageUrl = encodeURI(imageUrls.title.results[0]);
      this.contactImageUrl = encodeURI(imageUrls.contact.results[0]);
    })
  );
}

initData2(): Observable<any> {  // <-- return observable here
  // use `forkJoin` function to trigger multiple observables in parallel
  return forkJoin({
    title: this.dataService.getTitleImageUrl(this.data.titlId, this.data.id),
    contact: this.dataService.getTitleImageUrl(this.data.titlId, this.data.id)
  }).pipe(
    // use `tap` operator to perform side-effects
    tap(imageUrls => {
      this.titleImageUrl = encodeURI(imageUrls.title.results[0]);
      this.contactImageUrl = encodeURI(imageUrls.contact.results[0]);
    })
  );
}

And later you could use higher order mapping operator (for co-dependent) observables to map from one observable to another

ngOnInit() {
  this.initData1().pipe(
    switchMap(imageUrls => this.initData2())
  ).subscribe(
    response => { 
      // response from `this.initData2()`
    },
    error => {
      // handle errors
    }
  );
}

Further information on handling nested subscriptions here.

ruth
  • 29,535
  • 4
  • 30
  • 57
1

You can simply call the second function initData2(); inside the response block of first function call.

initData1(){
    this.httpClient.get(yourURL).subscribe(response => {
        initData2();
    })
}

In this way it will call one after another.

Tushar
  • 1,948
  • 1
  • 13
  • 32