Run Promises in a loop

In this revision, I do not see anywhere that the filter property of the search options is being set.

Thanks for noticing! I did update the code - Didn’t make a difference though…

Just to give you a new line of thought, as the above code resolves the promises in parallel are you sure the plugin can handle multiple requests simultaneously and is not silently dying? Given the use case of a Contacts class for mobile, I’d rather think one wouldn’t need to handle multiple simultaneous requests in general. So, in this case the plugin might not be working in the way you might be thinking it is.

Thanks KishuPro - Yes, maybe I shouldn’t assume that because it works with nested promises, it should work with Promise.all() as well.

I’ve been thinking I may have to resort to plan B - that is, getting the user to pick the contacts themselves for the SW to perform actions on it. It’s just more cumbersome for the user, but maybe I shouldn’t expect it to be too easy to manipulate a device’s contact list.

1 Like

Perhaps, if possible you can share a broader view of your requirements so that we can suggest you alternative ways of handling things or confirm that your current line of thought is the best option.

So this problem has gotten me intrigued. If it works when you chain the Promises, and you need to build a dynamic chain of Promises, here’s a way.

let arrayOfPromises = //your dynamically built array that you were using PromiseAll with

function chainTwoPromises(firstPromise: Promise<type>, secondPromise: Promise<type>) {
  return firstPromise.then(_ => secondPromise);
}

let resultAtEndOfChain = arrayOfPromises.reduce(chainTwoPromises);

You’d have to tweak this if some promises fail. But if every promise succeeds, the result variable will hold a promise that resolves to the value of the last Promise.

This work is for a client - I can say that I do have new data for an undetermined amount of contacts present in my device’s contact list.

So I need to update relevant contacts on the device by
1 - finding the contact from the device’s contact list (as a Contact object)
2 - updating some fields in that Contact

Hope that’s sufficient info.

Intriguing concept. I assume that resultAtEndOfChain points to the last Promise? Assuming this, I did

let resultAtEndOfChain: Promise<Contact> = prom_arr.reduce(this.chainTwoPromises);
      resultAtEndOfChain.then(result=>{
         // bind to template variable: 
        this.contactinfo = JSON.stringify(result);
      }).catch( err => {
        console.log(err);
      })

But that didn’t return any results…

If your business logic does not allow for update of the contacts programmatically (i.e. the user has to manually save each contact in any case) then the best option can be to show a list of some relevant data from your matchedContacts array. Then the user can choose a name from the list to edit and you can call contacts.find to get that particular contact. At this point, a form can be shown filled with the contact data so that the user can update it. In effect, this will be a manual iteration over the matchedContacts array.

On the other hand, if your business logic allows for programmatic update of the contacts without any user intervention as such, then the best way is to iterate over the matchedContacts array dynamically and call contacts.find for each of the elements to fill up a common array with the returned Contact[] from the .then method of the Promise. It can very well be done in sequence and should not be done in parallel.

Yes, I am currently doing it the first way - but the whole purpose of this post is on how to do it programatically. I’ve been unable to do it so far…

1 Like

I understand, but as I had promised to confirm whether what you are doing is the best option or not in my opinion, I just confirmed. Sorry I had to think from a level outside of this thread itself, as, to give you a genuine suggestion, I couldn’t have taken your idea and initial question for granted as the best way to solve your problem. I know whatever I am saying can be confusing, so nvm!

Anyways, what should be interesting to you is that there surely is a solution to dynamically achieve what you tried there without overloading the plugin. @AaronSterling I thought pointed you in the right direction, but as far as I can see, the sheer fact that his solution depends on the prom_arr, is not helping it. This is because when you create the array, you intentionally or not have to call the contact.find method and thereby overload the plugin.

Just to give you a hint, your problem is very much a fit case for a custom recursive function. It’s interesting indeed and I’ll try to implement the recursion I am talking about and give you some working code which you can adapt to your needs.

Thanks KishuPro - Looking forward to it!

Almost done :smiley: … I’ll just check it on the emulator.

Here is my code:

Declarations:

...

  resArr = [];
  matchedContacts = ["A", "B", "C", "D"];
  fieldTypes: ContactFieldType[] = ["name", "displayName"];
  options: ContactFindOptions = new ContactFindOptions();

...

You’ll call this function:

public modifyContacts() {
  this.platform.ready().then(() => {
    let count: number = 0;
    this.options.multiple = false;
    this.options.filter = this.matchedContacts[count];
    this.resolveAll(this.contacts.find(this.fieldTypes, this.options), count);
  });
}

The recursive method:

private resolveAll(p: Promise<Contact[]>, count: number) {
  p.then(carr => {
    this.resArr.push(carr);
    if (count < this.matchedContacts.length) {
      this.options.filter = this.matchedContacts[++count];
      this.resolveAll(this.contacts.find(this.fieldTypes, this.options), count);
    } else {
      // HERE is the data you are looking for
      console.log("resArr: " + JSON.stringify(this.resArr));
    }
  });
}

I’ve coded it to give you the essential idea, you can adapt it according to your needs now. Surely, you’ll have to do some validations and pick the exact data you need, but that should be trivial. The code should be inside a provider ideally. I checked it on my android emulator and it is working, hopefully it’ll work at your end too. Please confirm and do let me know if you’ve any questions.

2 Likes

Beautiful!!! This works very well on my real android device!

I just had to make a small change, pushing the result into resArr inside the if statement:

private resolveAll(p: Promise<Contact[]>, count: number) {
  p.then(carr => {
    if (count < this.matchedContacts.length) {
      this.resArr.push(carr[0]);
      this.options.filter = this.matchedContacts[++count];
      this.resolveAll(this.contacts.find(this.fieldTypes, this.options), count);
    } else {
      // HERE is the data you are looking for
      console.log("resArr: " + JSON.stringify(this.resArr));
    }
  });
}

Otherwise I had the first result printing twice, once at the start and once at the end. It’s been a while since I used a recursive function - forgotten how powerful they can be.

Many thanks for putting in the time, KishuPro, It’s greatly appreciated!

1 Like

You are welcome!! And thanks to you too for giving us an interesting problem, I enjoyed coding it!

http://jsbin.com/zecaxuzaso/3/edit?js,console

1 Like