1

I have a situation where I defined a variable diary: Diary in my typescript file. When the user clicks a certain save button I have to execute f1, a function having the following structure:

public f1() {
   if (condition 1) {
      this.service.serviceCall(param).subscribe(res =>
         diary.firstPage.push(res)
      )
   }

   if (condition 2) {
       this.service.serviceCall(param).subscribe(res =>
          diary.secondPage.push(res)
   }

   if (condition 3) { ... }

   ...
}

f1() is executed before f2() which does the following:

public f2() {
   this.diaryService.saveDiary(diary).subscribe();
}

Since f1 modifies the diary label, I have to make sure that f2 is executed only after all the subscriptions of f1 have been completed. How can I do that?

Rexam
  • 823
  • 4
  • 23
  • 42
  • 1
    Any logic that needs to be executed only after the observable is finished should go into the `subscribe(res => {})` block. –  Feb 23 '21 at 13:34
  • The problem is: where to start? I don't know which subscribe will be the first one in `f1()`. Sometimes only one will be executed, sometimes none, sometimes all. – Rexam Feb 23 '21 at 13:35

1 Answers1

2

Considering a Promise approach should be easy here, where you wait for all the responses and then finally make a save call:

public async f1() {
  try {
    if (condition 1) {
        const res = await this.service.serviceCall(param).toPromise();
        diary.firstPage.push(res)
    }

    if (condition 2) {
        const res = await this.service.serviceCall(param).toPromise();
        diary.secondPage.push(res)
    }

    //at the end
    this.f2();

  } catch() {
    // something heer
  }
}

This can also be tackled using maybe forkJoin, where you prepare the an array of Observables based on the conditions and finally make the f2 call in forkJoin subscription. This gives you an advantage of parallel calls.

ForkJoin

public f1() {
  const allApis: any = {};
  
  if (condition 1) {
    allApis.firstPage = this.service.serviceCall(param);
  }

  if (condition 2) {
      allApis.secondPage = this.service.serviceCall(param);
  }

  //at the end
  forkJoin(allApis).pipe(tap((responses) => {
    Object.entries(responses).forEach(([k, v]) => {
      diary[k].push(v)
    });
  })).subscribe(() => {
    this.f2()
  });
}
Ashish Ranjan
  • 12,760
  • 5
  • 27
  • 51
  • Something like this is exactly what I am looking for. I didn't consider using the `forkJoin` only after preparing the array of observables. Thanks! – Rexam Feb 23 '21 at 13:45
  • 1
    @Rexam: It just has a downside of waiting for each service call to finish before doing the next, forkJoin would take care of that. With some additional logic for updating the appropriate array for the responses. – Ashish Ranjan Feb 23 '21 at 13:55