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 .
×

[Help] Repeating Section var doesn't change/init

1610359164

Edited 1610394369
New to the custom sheet editing, but not to webdev. Since I can't tackle all of the under-the-hood stuff, I'm having trouble debugging an issue. The specific issue is that: for repeating_basicskills: regardless of it's corresponding characteristic value and toggle settings, it will always calculate as 25 in the roll, while the corresponding span will render the correct value based on the characteristic and all the toggles. for repeating_advancedskills: as above, but the roll will say that the attribute is not set, creating a message syntax error I have a repeating section for skill line entries, and scripted tracking their updating to happen on a number of triggers (characteristic choice, characteristic value change, skill level toggles[4]). It renders the value in a span over the roll button. The span renders the value correctly, and adjusts exactly as it should. However, when the button is clicked to roll the dice, it references a completely different value entirely, and this same value is used for every row in the repeating section. In a sibling section, it's even worse as it doesn't even get initialized/found so it throws a roll error, even though, again, the span display is showing correctly. I'll have snippets for the repeating section and the entire worker below, commented for legibility. <div class="sheet-3colrow"> <!-- Left Column --> <div class="sheet-col sheet-skills"> <hr> <h3>Basic Skills</h3> <table> <tr> <th>Skill Name</th> <th>Tr</th> <th>10</th> <th>20</th> <th>30</th> <th>Roll</th> </tr> </table> <fieldset class="repeating_basicskills"> <table> <tr> <td> <div class="sheet-row"> <div class="sheet-item sheet-bigger"> <input class="sheet-baseinfo" type="text" name="attr_basicskillname" /> </div> <div class="sheet-item sheet-med"> <select name="attr_basicskillcharacteristic" class="charaselect"> <option value="ws">(WS)</option> <option value="bs">(BS)</option> <option value="strength">(S)</option> <option value="toughness">(T)</option> <option value="ag">(Ag)</option> <option value="int">(Int)</option> <option value="per">(Per)</option> <option value="wp">(Wp)</option> <option value="fel">(Fel)</option> </select> </div> </div> </td> <td><input type="checkbox" name="attr_basicskill1" value="0.5" /></td> <td><input type="checkbox" name="attr_basicskill2" value="10" /></td> <td><input type="checkbox" name="attr_basicskill3" value="10" /></td> <td><input type="checkbox" name="attr_basicskill4" value="10" /></td> <td> <button type="roll" name="roll_basicskill" value="@{basicskillname}\n**TN**[[(@{basicskill}+?{Modifier|0})]]: [[1d100]]"> <span name="attr_basicskill"></span> </button> </td> </tr> </table> </fieldset> </div> <!-- Mid Column / Characteristics --> <div class="sheet-col sheet-characteristics"> <h3>Characteristics</h3> <button type="roll" name="roll_ws" value="Weapon Skill\n**TN**[[(@{ws}+?{Modifier|0})]]: [[1d100]]"><label>Weapon Skill (WS)</label></button><br> <input type="text" name="attr_ws" value="0" /> <button type="roll" name="roll_bs" value="Ballistic Skill\n**TN**[[(@{bs}+?{Modifier|0})]]: [[1d100]]"><label>Ballistic Skill (BS)</label></button><br> <input type="text" name="attr_bs" value="0" /> <button type="roll" name="roll_strength" value="Strength\n**TN**[[(@{strength}+?{Modifier|0})]]: [[1d100]]"><label>Strength (S)</label></button><br> <input type="text" name="attr_strength" value="0" /> <button type="roll" name="roll_toughness" value="Toughness\n**TN**[[(@{toughness}+?{Modifier|0})]]: [[1d100]]"><label>Toughness (T)</label></button><br> <input type="text" name="attr_toughness" value="0" /> <button type="roll" name="roll_ag" value="Agility\n**TN**[[(@{ag}+?{Modifier|0})]]: [[1d100]]"><label>Agility (Ag)</label></button><br> <input type="text" name="attr_ag" value="0" /> <button type="roll" name="roll_int" value="Intelligence\n**TN**[[(@{int}+?{Modifier|0})]]: [[1d100]]"><label>Intelligence (Int)</label></button><br> <input type="text" name="attr_int" value="0" /> <button type="roll" name="roll_Per" value="Perception\n**TN**[[(@{per}+?{Modifier|0})]]: [[1d100]]"><label>Perception (Per)</label></button><br> <input type="text" name="attr_per" value="0" /> <button type="roll" name="roll_Wp" value="Willpower\n**TN**[[(@{wp}+?{Modifier|0})]]: [[1d100]]"><label>Willpower (Wp)</label></button><br> <input type="text" name="attr_wp" value="0" /> <button type="roll" name="roll_Fel" value="Fellowship\n**TN**[[(@{fel}+?{Modifier|0})]]: [[1d100]]"><label>Fellowship (Fel)</label></button><br> <input type="text" name="attr_fel" value="0" /> </div> <!-- Right Column --> <div class="sheet-col sheet-skills"> <hr> <h3>Advanced Skills</h3> <table> <tr> <th>Skill Name</th> <th>Tr</th> <th>10</th> <th>20</th> <th>30</th> <th>Roll</th> </tr> </table> <fieldset class="repeating_advancedskills"> <table> <tr> <td> <div class="sheet-row"> <div class="sheet-item sheet-bigger"> <input class="sheet-baseinfo" type="text" name="attr_advancedskillname" /> </div> <div class="sheet-item sheet-med"> <select name="attr_advancedskillcharacteristic" class="charaselect"> <option value="ws">(WS)</option> <option value="bs">(BS)</option> <option value="strength">(S)</option> <option value="toughness">(T)</option> <option value="ag">(Ag)</option> <option value="int">(Int)</option> <option value="per">(Per)</option> <option value="wp">(Wp)</option> <option value="fel">(Fel)</option> </select> </div> </div> </td> <td><input type="checkbox" name="attr_advancedskill1" value="0.5" /></td> <td><input type="checkbox" name="attr_advancedskill2" value="10" /></td> <td><input type="checkbox" name="attr_advancedskill3" value="10" /></td> <td><input type="checkbox" name="attr_advancedskill4" value="10" /></td> <td> <button type="roll" name="roll_advancedskill" value="@{advancedskillname}\n**TN**[[(@{advancedskill}+?{Modifier|0})]]: [[1d100]]"> <span name="attr_advancedskill"></span> </button> </td> </tr> </table> </fieldset> </div> </div> <script type="text/worker"> // libs designed for dynamic processing of "hardcoded" skills // "speaklow" is the only advanced skill, the rest are basic skills const attributes = ['ws', 'bs', 'strength', 'toughness', 'ag', 'int', 'per', 'wp', 'fel'] const skills = { ws: ['parry'], bs: [], strength: ['athletics'], toughness: [], ag: ['acrobatics', 'dodge', 'stealth'], int: ['logic', 'speaklow'], per: ['awareness', 'scrutiny'], wp: [], fel: ['charm', 'command', 'deceive', 'inquiry'] } // this is to set up all listeners on a per attribute basis attributes.forEach(attribute => { // update skills on attribute change and sheet open on(`change:${attribute} sheet:opened`, () => {             // set skill value for each hardcoded skill skills[attribute].forEach(skill => setSkillVal(attribute, skill))             // get ids for all the basic skills to see which need to be updated getSectionIDs("basicskills", basicSkillIDs => { // get all of their characteristics getAttrs(basicSkillIDs.map(id => `repeating_basicskills_${id}_basicskillcharacteristic`), basicSkillAttributeList => { for (const key in basicSkillAttributeList) {                         // if the attribute of the current id matches the current attribute if (basicSkillAttributeList[key] === attribute) {                             // take the id out of the key and join into direct name for setSkillValue     const id = key.split('_')[2] setSkillVal(attribute, `repeating_basicskills_${id}_basicskill`) } } }) })             // same as above, but for advanced skills getSectionIDs("advancedskills", advancedSkillIDs => { // get all of their characteristics getAttrs(advancedSkillIDs.map(id => `repeating_advancedskills_${id}_advancedskillcharacteristic`), advancedSkillAttributeList => { for (const key in advancedSkillAttributeList) { if (advancedSkillAttributeList[key] === attribute) { const id = key.split('_')[2] setSkillVal(attribute, `repeating_advancedskills_${id}_advancedskill`) } } }) }) }) // update skill toggle change skills[attribute].forEach(skill => { on(`change:${skill}1 change:${skill}2 change:${skill}3 change:${skill}4`, () => { setSkillVal(attribute, skill) }) }) }) // end attributes.forEach     // special case for skills with their own characteristic dropdown list const multiAttributeSkill = ['gamble', 'intimidate'] multiAttributeSkill.forEach(skill => {         // track for skill toggle and characteristic changes (and sheet opened), and yes I am missing tracking on attribute updates on(`change:${skill}1 change:${skill}2 change:${skill}3 change:${skill}4 change:${skill}characteristic sheet:opened`, () => {             // get the characteristic value based on it's current setting getAttrs([`${skill}characteristic`], skillCharacteristic => { const { [`${skill}characteristic`]: attribute } = skillCharacteristic setSkillVal(attribute, skill) }) }) })     // lib of the repeating_basicskills for legibility const repeatingBasicSkillEventsList = [ "change:repeating_basicskills:basicskill1", "change:repeating_basicskills:basicskill2", "change:repeating_basicskills:basicskill3", "change:repeating_basicskills:basicskill4", "change:repeating_basicskills:basicskillcharacteristic", ]     // track event on any of the toggles or characteristic change on(repeatingBasicSkillEventsList.join(' '), ({sourceAttribute}) => {         // get the current characteristic of the skill, can ignore true id since in direct scope of event on repeating features getAttrs(["repeating_basicskills_basicskillcharacteristic"], ({repeating_basicskills_basicskillcharacteristic: attribute}) => {             // using the sourceAttribute, remove the component and replace with the keyword for the skill value let splitSourceAttribute = sourceAttribute.split("_") splitSourceAttribute.pop() splitSourceAttribute.push("basicskill") const skillName = splitSourceAttribute.join("_") setSkillVal(attribute, skillName) }) })     // same as above, just for advancedskills const repeatingAdvancedSkillEventsList = [ "change:repeating_advancedskills:advancedskill1", "change:repeating_advancedskills:advancedskill2", "change:repeating_advancedskills:advancedskill3", "change:repeating_advancedskills:advancedskill4", "change:repeating_advancedskills:advancedskillcharacteristic", ] on(repeatingAdvancedSkillEventsList.join(' '), ({sourceAttribute}) => { getAttrs(["repeating_advancedskills_advancedskillcharacteristic"], ({repeating_advancedskills_advancedskillcharacteristic: attribute}) => { let splitSourceAttribute = sourceAttribute.split("_") splitSourceAttribute.pop() splitSourceAttribute.push("advancedskill") const skillName = splitSourceAttribute.join("_") setSkillVal(attribute, skillName) }) })     // this func is what actually sets skills, given the attribute needed and the name of the skill     // for repeating skills, [skill] will be the direct ref w/ id     // [skill]1/2/3/4 are the toggles function setSkillVal(attribute, skill) { getAttrs([attribute, `${skill}1`, `${skill}2`, `${skill}3`, `${skill}4`], trainings => { const { [attribute]: base, [`${skill}1`]: trained=0, [`${skill}2`]: adv1=0, [`${skill}3`]: adv2=0, [`${skill}4`]: adv3=0 } = trainings             // math to correctly process skill value const skillScore = Math.floor((Number(trained) + 0.5) * Number(base)) + Number(adv1) + Number(adv2) + Number(adv3)             // skill names are just the skill name, or basicskill/advancedskill for the repeating setAttrs({ [skill]: skillScore }) }) } </script> Edit for clarity in the byproducts, and again to update with what HTML should be needed to run.
1610361976
GiGs
Pro
Sheet Author
API Scripter
I dont follow exactly what the issue is, and I lack enough code to be able to test it and examine it properly. The sheet worker refers to attributes that aren't in the html above, I think. But despite that i see a couple of things thatsuggest to m e you will have async issues leafing to incorrect values. First from an efficiency point of view, you never want to set up a function containing getAttrs and setAttrs, inside  another getAttrs and especially not inside a loop. getAttrs and setAttrs (and getSectionIDs, yoo) are asynchronous functions, meaning that you have no control over exactly when they run and what order they'll finish in. They are also very slow, especially setAttrs, and that should absolutely never be inside a loop. I'd recommend restructuring your setSkillVal   function so it doesnt contain a getAttrs or setAttrs function, in instead you pass values to it, and it performs calculations and returns the calculated value to the calling worker. And for workers where you are doing multiple attributes at once, set up an object to hold the calculated values,  and save them all using setAttrs in one operation, structured something like (this is obviously not real code): const output = {} for each attribute     output[attribute_name] = getSkillValue(values,attribute_name)  next setAttrs(output) This might not be related to your problem, but it will make the code much more efficient. Unfortunately, your code is too complex to see what the issue is just from looking at it. I'd need to be able run and test it.
1610392467

Edited 1610394449
GiGs said: I dont follow exactly what the issue is, and I lack enough code to be able to test it and examine it properly. The sheet worker refers to attributes that aren't in the html above, I think. <button type="roll" name="roll_basicskill" value="@{basicskillname}\n**TN**[[(@{basicskill}+?{Modifier|0})]]: [[1d100]]"> <span name="attr_basicskill"></span> </button> The issue is that even though the button's roll references `basicskill` and the span refferences `basicskill`, they are both set to different values. For each individual row of the repeating section, the span will show the row's correct value in the span, but will always have a value of 25 in the roll. GiGs said: getAttrs and setAttrs (and getSectionIDs, yoo) are asynchronous functions, meaning that you have no control over exactly when they run and what order they'll finish in. They are also very slow, especially setAttrs, and that should absolutely never be inside a loop. That is the entire point of the callback in an asyncronous function. Once the async function finishes, it will send it's return to the callback. That way, it will execute in a synchronous fashion. For certain parts of the code, I might be able to consolidate into a single setAttr, but there are parts that I cannot because of the dynamic nature of what characteristic the skill uses could be. I have to look up what characteristic is used, then can lookup the value of that characteristic. Edit: I updated the original HTML portion of the code with the minimum of what's needed to run the code sample. I haven't tested it in another game yet, but it will function with what's given, though not super pretty to look at.
1610394412

Edited 1610394654
Andreas J.
Forum Champion
Sheet Author
Translator
Maybe the attribute isn't correctly saved due to only being represented by an span, and not an input/textarea? If that's the case, adding an <input type="hidden" name="basicskill"> alongside the span could solve the situation. Any idea where the value of "25" could come from? Is that a default, or a possible option with the checkboxes? Figuring out how it gets the odd value can help figuring out what's wrong. Usually when I see people doing <span> to display an attribute, people have a hidden input on the sheet with the same name, but not sure if that's strictly necessary or just something people do. Just haven't seen the <span> thing on a repeating section until now.
1610394553

Edited 1610394953
I'll give that a shot. I had been reading over the docs, and they said that using inputs was a non-performant way of doing things (not to mention that it had to be updated anyway since the old disabled inputs were blocking event propagation to the button). Edit: Welp, that did it. Not quite sure it doesn't work otherwise, but I'll take it. Thanks. Edit for possible clarification: ᐰndreas J. said: Any idea where the value of "25" could come from? Is that a default, or a possible option with the checkboxes? Figuring out how it gets the odd value can help figuring out what's wrong. I can see this as possible haven gotten set by a value earlier on in my development. Looking at the "Attributes & Abilities" tab shows basicskill set to 25, and no advancedskill. Might have been from looking at a different sheet format as well. Guess I should have deleted the character and made a new one to get a clean sheet when checking out sheets.