Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Waiting to finish looping through getSectionIDs()?

I'm making a worker that looks through several repeating sections, grabs a certain value from each of them, and adds them all together. This all hinges on running through a loop that calls getSectionIDs() for each relevant section and, because it's asynchronous, the variable I'm storing the results in is empty when I try to use it. I have it set up with a promise right now (which I honestly barely understand), but it still gives the same result. // 'modSections' contains a list of names for sections that are to be used in this function. // 'modNames' contains a list of attribute names formatted for the user // 'attrNames' contains a list of the actual attribute names used on the sheet (matches up with 'modNames') modSections.forEach(function(value) {   // Create listener for each section with modifiers   on(`change:repeating_${value}:${value}mods`, function()   {     // Build query for getAttrs() for each section with modifiers     var makeQuery = new Promise(function(resolve)     {       var query = [];       modSections.forEach(function(section) // For each repeating section...       {         getSectionIDs(section, function(ids) // ...get a list of IDs in that section...         {           ids.forEach(function(id) // ...and for each ID...           {             // ...add it to the query             query.push(`repeating_${section}_${id}_${section}mods`);           });         });       });       resolve(query);     });     var setMods = function()     {       makeQuery.then(function(query)       {         getAttrs(query, function(modInputs) // Get all modifier strings from all repeating sections         {           var modString = "";           query.forEach(function(q) // Combine all modifier strings into one string           {             modString.concat(modInputs[q]);             modString.concat(","); // Comma separator           });                     mods = modString.replace(" ", "").toLowerCase().split(",").filter(Boolean); // Cleaning up and splitting into individual modifier strings           var modTotals = new Array(modNames.length);           modTotals.fill(0);           mods.forEach(function(mod)           {             let props = mod.split(":"); // Separate each modifier into its properties             modTotals[modNames.indexOf(props[0])] += parseInt(props[1]); // Total up all properties for each attribute name           });           for(i = 0; i < modTotals.length; i++)           {             let attrName = attrNames[i];             let modTotal = modTotals[i];             setAttrs({               attrName : modTotal             });           }         });       });     }     setMods();   }); });
1596010788
Finderski
Plus
Sheet Author
Compendium Curator
Just put everything inside the getSectionIDs.  
1596020865
GiGs
Pro
Sheet Author
API Scripter
Finderski is correct, and you should go further. You just want one getSectionIDs call - you definitely shouldnt have it inside a loop. So what you do is have on on(changet) line, then getSectionIDs, where you loop through the id arrays to build an array of attribute names. You dont use them at this stage. Then have just one getAttrs line with all those names. then initialise an output variable to store planned changes to the sheet. Now loop through the section ids array again, and this is where you do your work. You store that work in the previous output object. Finally, when all is complete, you have one setAttrs that saves everything in the output variable in one step. getSectionIDs, getAttrs, and setAttrs are the heaviest functions you'll use in sheet workers, and too many of them creates very noticeable lag. You should never have any of then them inside loops. This procedure means you just need one of each.
1596023293

Edited 1596023401
GiGs
Pro
Sheet Author
API Scripter
I just noticed you have multiple section names to check, that does make things a lot more complicated. Note: promises dont work in the version of javascript available to us in sheet workers.  The second-easiest way to handle this is to hardcode them and have a nested set of getSectionIDs. You'd use the structure i described earlier, but would start with a russian dll-nesting set of getAectionIDs, each using different array names, and then at the bottom, a single getAttrs, and setAttrs as described previously.  The hardest option is looking into callbacks. With multiple getSectionIds, that is going to be a lot more complex to write. This is the only promise-like option available in sheet workers. The easiest solution would be to have one sheet worker per section, have it each save an intermediate result for that section to a hidden attribute on the sheet. And have one final sheet worker that monitors those intermediate attributes for changes, and adds them up, saving it to the final destination. The latter is the easiest to write, but is least efficient.
I think I'll try setting it up with a hidden attribute in each section. That's actually going to reduce the load from what I'm trying to do right now since it doesn't have to iterate through every section when one of them is changed. Thank you!
Okay, a smaller issue came up after I got all of that working. I'm just going to post it in the same thread because it's probably just me not understanding how to use setAttrs (the wiki is very little help for anything outside of simple cases). var attr = `${section}modstotal`; setAttrs({   attr: modString }); How do I pass the name of the attribute to be set as a variable?
1596033208
GiGs
Pro
Sheet Author
API Scripter
you need to enclose in square brackets like so var attr = `${section}modstotal`; setAttrs({   [attr]: modString }); if you are doing it and not using it for anything else, you can also do setAttrs({   [`${section}modstotal`]: modString });
Once again, thank you so much. Please accept this deep dish pizza as a token of my appreciation.