1

Please let me know if I have to provide any more code or explanations.

I am trying to execute some code after I call a service method inside a for loop. I tried two different ways.

In 1st method, the console.log('1st After for loop') which after the for loop is printing before it prints the console.log(data)

In 2nd method, the console.log('2nd- After for loop') is never printing.

I want to loop through the list. Validate each item. If not validation not successful, show ask for a confirmation. If user selects Yes, the call save method.

Code snippet #1:

save() {
  this.selectRowData.forEach(async s => {
    this.myService.validate(s.id).subscribe(data => {
      console.log(data);
      if(data) {
         this.myService.confirm('Please confirm..', 'Selected Rule do not match expected rules. \n Do you want to continue? ', 'Yes', 'No')
      .then((confirmed) => {
        if(confirmed) {
          console.log("User selected: Yes");
         this.myService.save();
        } else {
          console.log("User selected: No");
        }
      }).catch(() => {
        console.log("Error...");
      });
    }, (error: any) => {
      alert("Error Linking Lot");
    });
  });
  console.log('1st After for loop');
}

Code snippet #2:

async save() {
  await new Promise(resolve => {
    this.selectRowData.forEach(async s => {
      let validateData = await this.myService.validate1(s.id);
      console.log(validateData);
    });

  });
  console.log('2nd- After for loop');
}

service.ts

validate(id: string): Observable < boolean > {
  return this.httpClient.get < boolean > ('/RestWeb/validate?id=' + id);
}

validate1(id: string) {
  return this.httpClient.get < boolean > ('/RestWeb/validate?id=' + id).toPromise();
}
1
  • Try using setTimeout() function. Commented May 20, 2021 at 4:43

1 Answer 1

3

There are various issues with your implementation.

Issues with the save method:

  1. You're using async which only works on methods that return a promise.
  2. You're calling validate method on the myService in the callback method, which returns an Promise Observable.
  3. You could've used used await in there if the validate method returned a Promise. But it returns an Observable.
  4. forEach runs synchronously but the myService.validate method runs asynchronously and so will the callback method inside the success callback to the .subscribe method.

That's the reasons why it's logging '1st After for loop' before logging the results.

Issue with the async save method:

You're awaiting the new Promise inside the method but not rejecting or resolveing that promise.

That's probably why the '2nd- After for loop' isn't even logging.

A better way would be to either use the RxJS forkJoin operator to join all the Observables returned by the myService.validate method and then log inside the success callback to the subscribe method. Something like this:

forkJoin(
  this.selectRowData.map(({ id }: any) => this.myService.validate(id))
).subscribe(
  data => {
    console.log('save:: ', data);
    console.log('save:: 1st After for loop');
  },
  (error: any) => {
    alert('save:: Error Linking Lot');
  }
);

Alternatively, if you want to go with the promise approach(which wouldn't make much sense since you're using RxJS), you could also use Promise.all, await it and then log the results, and then the message. Something like this:

async saveAsync() {
  const responses = await Promise.all(
    this.selectRowData.map(({ id }: any) => this.myService.validate1(id))
  );
  console.log('saveAsync:: ', responses);
  console.log('saveAsync:: 2nd- After for loop');
}

Here's a Working Sample StackBlitz for your ref. Please check the console for the result.

Sign up to request clarification or add additional context in comments.

4 Comments

it's unnecesary use the spread operator (the ...) both in const observables and in forkJoin. use simple: observables=this.selectRowData.map(x=>this.myService.validate(s.id)) and forkJoin(observables)
Thanks a lot for the explanation. upvoted for now. it gave me a lot of idea now. I tried with my code, it is working. I am sorry, I didn't explain the entire scenario. Now I have updated the code and what I actually want. with my requirement, I am still stuck. when I try to call save for each element, I am not getting the result from validate method.
@SK. we're supposed to keep threads focused here on StackOverflow. So I'd recommend reverting the question update, closing this loop, and asking a new question with this issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.