0

In the below code, I have a for loop inside that one API is getting called. I want the 1st API call to be finished and code inside subscribe fully executes first and then the next iteration of for loop will begin and again the API call will be triggered for the next iteration.

But currently the APIs are executing in parallel mode. But I want the APIs to be executed in sequential manner.

                      parentLevelIdArray.forEach(parentLevelId => {
                        this.locModService.deleteAPI(parentLevelId, levelObj.id)
                        .subscribe((response) => {
                          if (response.status === 200) {
                            this.message = 'Image uploaded successfully';
                            this.getSublevels();
                            this.getAllLinkedLevel();
                          } else {
                            this.message = 'Image not uploaded successfully';
                          }
                        }
                        )
                      });

I have checked other stackoverflow links but didn't get the actual answer for my case. Please help.

Surya
  • 604
  • 1
  • 6
  • 25
  • You can't. `forEach` is synchronous. Subscription notifications are asynchronous. If you want to do something asynchronous in series, see the "series" part of [my answer here](https://stackoverflow.com/a/43766002/157247). The mechanics are *slightly* different for subscriptions vs. promises, but the concepts are the same. – T.J. Crowder Aug 12 '21 at 09:21
  • Closely related: https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop – T.J. Crowder Aug 12 '21 at 09:22
  • look for `forkJoin` – Eliseo Aug 12 '21 at 09:43
  • @T.J.Crowder Thanks. It would be great if you help me with the code snippet in terms of my case. – Surya Aug 12 '21 at 10:02
  • I haven't done Angular in years. I could show you **a** way to do it, but there's probably a better Angular-specific way. Are you sure you want these done in *series*, not in *parallel*? Because @Eliseo has pointed you at something that handles the parallel case in an Angular way. – T.J. Crowder Aug 12 '21 at 10:18
  • @T.J.Crowder Okay. No probs. Yes, I wanted to do in series. I have written a recursive method and it resolved it. I have posted in the Answer section. – Surya Aug 12 '21 at 12:00

2 Answers2

0

The way I would do this is to turn that into an array of observables, like so:

const tasks = parentLevelIdArray.map((parentLevelId) => this.locModService.deleteAPI(parentLevelId, levelObj.id))

This way you can use the concat function to do this sequentially as you need:

concat(tasks).subscribe((response) => {
  if (response.status === 200) {
    this.message = 'Image uploaded successfully';
    this.getSublevels();
    this.getAllLinkedLevel();
  } else {
    this.message = 'Image not uploaded successfully';
  }
}
Octavian Mărculescu
  • 4,312
  • 1
  • 16
  • 29
0

I have resolved that with a recursive method.

Caller method --

let lastIndex = parentLevelIdArray.length - 1;
this.recursiveDelete(parentLevelIdArray, levelObj, lastIndex);

Calling method --

recursiveDelete(parentLevelIdArray, levelObj, lastIndex) {
      if(lastIndex >= 0) {
        this.locModService.deleteAPI(parentLevelIdArray[lastIndex], levelObj.id)
        .subscribe((response) => {
          //console.log("Inside subscribe()...");
          if (response.status === 200) {
            this.message = 'Image uploaded successfully';
            this.getSublevels();
            this.getAllLinkedLevel();
            lastIndex = lastIndex - 1;
            this.recursiveDelete(parentLevelIdArray, levelObj, lastIndex);
          } else {
            this.message = 'Image not uploaded successfully';
          }
        }
        )
      }
  }
Surya
  • 604
  • 1
  • 6
  • 25
  • 1
    I very much enjoy writing less code rather than more, but I am glad that you figured it out. – Octavian Mărculescu Aug 12 '21 at 12:08
  • Be careful, you never unsubscribe the subscriptions from `this.locModService.deleteAPI(..).subscribe(..)`. You should do this if you want to avoid any memory leak – Pilpo Aug 12 '21 at 12:23
  • 2
    @Pilpo There is no risk here, as the subscriptions are generated by http calls. Those complete after they emit the result of the request. – Octavian Mărculescu Aug 12 '21 at 12:27