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

GetAttrs isn't triggering before following code

1669328875

Edited 1669332799
I'm creating a new character sheet, but I'm having difficulty creating a universal updater for stats.  The issue I'm running into involves the asynchronous nature of the getAttrs() function, I think. The HTML code I am using for the test is below and displays as expected: <input type = "input" name = "agility"/> <select name = "attr_upd_atr"> <option value = "agility">Agility</option> <option value = "body">Body</option> <option value = "charisma">Charisma</option> <option value = "edge">Edge</option> <option value = "essence">Essence</option> <option value = "intuition">Intuition</option> <option value = "logic">Logic</option> <option value = "magic">Magic</option> <option value = "pain_res">Pain Resistance</option> <option value = "reaction">Reaction</option> <option value = "strength">Strength</option> <option value = "willpower">Willpower</option> </select> <br> <input type = "number" name = attr_upd_atr_val"/> On a change to the upd_atr_val, the sheet worker triggers, but as it runs through the code, the getAttrs call doesn't get processed until after the following loop to set the correct attribute (this loop currently is not finished, so does not actually do anything other than play stubs to track the progress of the program.) Sheetworker Javascript is here: <script type="text/worker"> const stats = ["agility", "body", "charisma", "edge", "essence", "intuition",  "logic", "magic", "pain_res", "reaction", "strength", "willpower"]; on("change:upd_atr_val", function(input_info) { let atr_value = parseInt(input_info.newValue)||0; let atr_change = "test"; let atr_req = ["upd_atr", atr_change]; console.log(atr_value); getAttrs(["upd_atr"], function(values) { //following lines execute and display properly, but only after the next function call (the setAttrs call) runs console.log("update1 " + values.upd_atr); console.log("update3 " + atr_change); return values.upd_atr||""; console.log("update3 " + atr_change); }); //following line executes before preceding console.log messages console.log("update2 " + atr_change); stats.forEach(function (stat) { //  this line also executes befor3e the getAttrs call complete // console.log([stat]); if (atr_change == [stat]) { getAttrs([stat], function(val2) { let val = (parseInt(val2[stat]))||0; // console.log(val); if (val != 0) { // console.log("operation"); } }); } }); }); </script>
1669576219

Edited 1669576373
Kavini
Pro
Marketplace Creator
Sheet Author
Compendium Curator
You're using multiple callback functions in parallel, in short: those two callback functions are (almost always) going to get executed in whatever order the server responds to them fastest. If you want to build on the results of the first function, you need to nest them. You probably also want to batch the looped getAttrs requests, because you're making an external call for each one which slows down your code a lot. You can do that like this: const stats = [ "agility", "body", "charisma", "edge", "essence", "intuition", "logic", "magic", "pain_res", "reaction", "strength", "willpower" ]; on("change:upd_atr_val", (eventInfo) => { const attrValue = parseInt(input_info.newValue) || 0; const attrChange = "test"; const request = [ "upd_atr", atr_change ...stats ]; getAttrs(request, (response) => { // Do something here with "upd_atr" stats.forEach((stat) => { if (attrChange === stat) { const val = parseInt(response[stat] || 0; if (val !== 0) { // Do something here with "stats" } } }); }); }); I made a few other changes, like converting your functions to arrow, and using consts wherever possible. Mostly these are just good stylistic choices, but I'd really read up on strict vs loose equality (== vs ===) in Javascript, because one day you'll come across it and you'll have no idea why your code is failing.
1669703141
GiGs
Pro
Sheet Author
API Scripter
That's a great modification of the code. I'd add to OP that you probably want to trigger a setAttrs at the end of your code. But with a loop, you run the risk of doing something like this: getAttrs ( request , ( response ) => {   // Do something here with "upd_atr"     stats . forEach (( stat ) => {     if ( attrChange === stat ) {       const val = parseInt ( response [ stat ] || 0 ;       if ( val !== 0 ) {         // Do something here with "stats"       }       setAttrs ({         stat : score       });     }   }); }); }); This is something you don't want to do, because you'll trigger a separate setAttrs call on each iteration of the loop. setAttrs functions are very slow, and can cause visible lagging of the sheet if you have enough of them. Instead you want something like this: getAttrs ( request , ( response ) => {   // Do something here with "upd_atr"     const output = {};   stats . forEach (( stat ) => {     if ( attrChange === stat ) {       const val = parseInt ( response [ stat ] || 0 ;       if ( val !== 0 ) {         // Do something here with "stats"       }       output [ stat + 'something' ] = calculation ;     }   });   setAttrs ( output ); }); }); Here we are creating a variable (output) to hold multiple values. Then on each iteration of the loop, the calculation is added to that output variable. It will hold whatever attribute names you want to save (inside the []  - the example here is pseudocode, you'll need to supply the appropriate attribute name) and the score you want to set that ttribute to after the =. Then single setAttrs sets multiple attributes at once.