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

Update all rows in a repeating section when an outside attribute changes

I have a repeating section in which values are determined by what attribute they are based on. I have the following sheet worker:     on("change:repeating_skills:skillattribute",function(eventInfo){         getAttrs([`dexterityTotal`,`insightTotal`,`empathyTotal`,`repeating_skills_skillattribute`],function(v){             const dex=parseInt(v.dexterityTotal);             const ins=parseInt(v.insightTotal);             const emp=parseInt(v.empathyTotal);             const att=v.repeating_skills_skillattribute;             const base=parseInt(v.repeating_skills_skillattribute);             let skill=0;             if(base>0){                 skill=base             }else{                 if(att=="dexterity"){                     skill=dex*2                 }                 if(att=="insight"){                     skill=ins*2                 }                 if(att=="empathy"){                     skill=emp*2                 }             }             setAttrs({[`repeating_skills_skilldie`]:skill});         });     }); I want it do this update not only when repeating_skills_skillattribute changes, but also whenever dexterityTotal, insightTotal, or empathyTotal are changed. So an event like: on("change:dexterityTotal change:insightTotal change:empathyTotal",function(eventInfo){      }); How do I cycle through all the rows in repeating_skills to update them?
1658122628
Kraynic
Pro
Sheet Author
You may be running into a capitalization issue.  I don't think you can use capitals in attributes in the change list. I'm not sure if you will need to change the html attribute names to match the lower case or not.  This is one reason that all example attributes in the wiki are lower case.  In any case, I would try ditching the capital Ts and seeing if that works for you.
1658126763

Edited 1658126876
John D.
Pro
Sheet Author
Randall, I believe you will need to cycle through every repeating skill by calling all the section IDs of the repeating section and iterating this sheet worker logic through each.  You probably don't need to touch each repeating section, just the one's that match the characteristic (i.e. dexterity, insight, or logic) that changed.  However, in this example below I just update all of them regardless. on ( "change:dexterityTotal change:insightTotal change:empathyTotal" , () => {     getSectionIDs ( 'skills' , skillIDs => {         const skillAttributes = [ `dexterityTotal` , `insightTotal` , `empathyTotal` ];         _ . each ( skillIDs , id => {             skillAttributes . push ( `repeating_skills_ ${ id } _skillattribute` );         });         getAttrs ( attributes , v => {             const dex = parseInt ( v . dexterityTotal );             const ins = parseInt ( v . insightTotal );             const emp = parseInt ( v . empathyTotal );             const updateSkills = {};             _ . each ( skillIDs , id => {                 const att = v [ `repeating_skills_ ${ id } _skillattribute` ];                 const base = parseInt ( v [ `repeating_skills_ ${ id } _skillattribute` ]) || 0;                 const skill =                     base > 0 ? base :                     att === "dexterity" ? dex * 2 :                     att === "insight" ? ins * 2 :                     att === "empathy" ? emp * 2 :                     false ;                 if ( skill !== false ) {                     updateSkills [ `repeating_skills_ ${ id } _skilldie` ] = skill ;                 }             });             setAttrs ( updateSkills ,{ silent : true });         });     }); }); Something I don't get is how you can have a string like "dexterity" and a numerical value out of the same repeating attribute: const att=v.repeating_skills_skillattribute; const base=parseInt(v.repeating_skills_skillattribute); Does this actually work for you, or is this non-functional example code?
1658134879
GiGs
Pro
Sheet Author
API Scripter
John is correct about iterating through the repeating section rows. I'd like to explain why. Your code uses this syntax: repeating_skills_skillattribute This is actually a very special syntax intended for a specific purpose. Each attribute in a repeating section can be duplicated across multiple rows, and Roll20 needs a way to know which you mean. So, behind the scenes, it creates a unique ID, for each row. They look like random strings of letters and numbers, like -y47hwtyw876. So the real name of an attribute might be repeating_skills_-y47hwtyw876_skillattribute Now, when you make a change entirely wthin a repeating section, like say change an stat which then adds the stat bonus in another input, you are working on only one row, and Roll20 can supply the row id automatically, so this syntax works: repeating_skills_skillattribute But if stats outside the repeating section affect it, a change to one of them can effect every row of the repeating section, so that syntax won't work. Luckily there is a function that gives you all the rwo ids - getSectionIDs. You can use that as John has, to build an array of all the rows attributes, so you can get their values with getAttrs, and then later, perform the calculation on every row in the section.
1658135261

Edited 1658135331
GiGs
Pro
Sheet Author
API Scripter
John D. said: Something I don't get is how you can have a string like "dexterity" and a numerical value out of the same repeating attribute: const att=v.repeating_skills_skillattribute; const base=parseInt(v.repeating_skills_skillattribute); Does this actually work for you, or is this non-functional example code? That's a good question, and does look like an error. Maybe it should be const att=v.repeating_skills_skillattribute; const base=parseInt(v[att]); or const att=v.repeating_skills_skillattribute; const base=parseInt(v[att + "Total"]); We'd need to see the html to know one way or another. Either way, it would need the id added, in the loop. By the way, Jon, the first line of your code has an issue. It should be on("change:dexteritytotal change:insighttotal change:empathytotal", () => { attributes there must be entirely lower case. If you don't, sooner or later, roll20 will fail to detect a change in that attribute.
1658147666

Edited 1658147921
The code works. It updates the row whenever the value in the row is changed. The problem is that I need another worker to update all the rows whenever a base attribute is changed, and the base attributes are outside the repeating section.
The attribute names cannot have capital letters? I thought that was only for repeating sections.
Got it! starting with John D's snippet I ended up with this, which does the job:     on("change:dexterityTotal change:insightTotal change:empathyTotal", () => {         getSectionIDs('skills', skillIDs => {             const skillAttributes = [`dexterityTotal`,`insightTotal`,`empathyTotal`];             _.each(skillIDs, id => {                 skillAttributes.push(`repeating_skills_${id}_skillattribute`);             });             getAttrs(skillAttributes, v => {                 const dex = parseInt(v.dexterityTotal);                 const ins = parseInt(v.insightTotal);                 const emp = parseInt(v.empathyTotal);                 const updateSkills = {};                 _.each(skillIDs, id => {                     const att = v[`repeating_skills_${id}_skillattribute`];                     const base = parseInt(v[`repeating_skills_${id}_skillattribute`]) || 0;                     let skill=0;                     if(base>0){                         skill=base                     }else{                         if(att=="dexterity"){                             skill=dex*2                         }                         if(att=="insight"){                             skill=ins*2                         }                         if(att=="empathy"){                             skill=emp*2                         }                     }                     setAttrs({[`repeating_skills_${id}_skilldie`]:skill});                 });             });         });     });
1658165701

Edited 1658165854
John D.
Pro
Sheet Author
Randall, Glad you got it working!  I wanted to follow-up on what GiGs said and the structure of your original code. On the matter of case, I'm foggy on the details but it may just be that repeating section attributes are evaluated in lowercase.  Regardless, the only thing I've ever ran into that required original case is in the creation and application of section IDs.  Such as when programmatically creating repeating sections.  Since attributes are evaluated in lowercase, as a best practice, all attributes should be handled in lowercase.  If camelCase is what you're used to, consider using underscores instead.  Variable names are fine in camelCase, it's the actual HTML sheet attributes in question here. This was a good catch on GiGs' part, I'd copied your code verbatim and didn't make the necessary alterations. On the matter of your original code, it could run more efficiently in two places: Working on an assumption here, but it seems to me that your skills will only have one characteristic associated with them, i.e. dexterity, insight, or empathy.  However, your code uses 'if' statements which will evaluate each section of characteristics and would be unnecessary if my assumption is correct.  Seems like GiGs and I were just having a duel of perspectives on this recently!  ;)  The better approach would be to use 'else if' instead so that only the characteristic that is required would be considered rather than going through all of them, such as: if ( base > 0 ){     skill = base } else {     if ( att == "dexterity" ){         skill = dex * 2     }     else if ( att == "insight" ){         skill = ins * 2     }     else if ( att == "empathy" ){         skill = emp * 2     } } The code I supplied originally was a condensed version of this, but logically it would bear the same result: The second piece is the setAttrs() call.  For optimal performance, you should try to limit getAttrs() and setAttrs() to one call each in a sheet worker.  Since the setAttrs() here is nested in a loop, you are going to perform a setAttrs() for each repeating skill on the sheet.  This is also why I built an object of repeating skills to write to as these can all be written at the same time in a single setAttrs() call. If you have any questions about any of this, I'm happy to help and explain.
Thanks. I liked the condensed code, but I couldn't get it to work, so I played around with using the parts that I knew were already working. Unfortunately, I don't really know what I'm doing, so I end up with messy code and a lot of cutting and pasting. As long as it works in the end, I'm good.
1658174126
John D.
Pro
Sheet Author
If it's feasible for you to post your HTML and CSS files here, or in GitHub, I'm happy to troubleshoot.  I was coding from the hip and I never doubt my ability to screw something up, but without seeing the code in action it's difficult to pin point what the problem could be. However, if that original code block of yours works in the overall sheet worker I drafted up, then this should work: on ( "change:dexteritytotal change:insighttotal change:empathytotal" , () => {     getSectionIDs ( 'skills' , skillIDs => {         const skillAttributes = [ `dexteritytotal` , `insighttotal` , `empathytotal` ];         _ . each ( skillIDs , id => {             skillAttributes . push ( `repeating_skills_ ${ id } _skillattribute` );         });         getAttrs ( skillAttributes , v => {             const dex = parseInt ( v . dexteritytotal );             const ins = parseInt ( v . insighttotal );             const emp = parseInt ( v . empathytotal );             const updateSkills = {};             _ . each ( skillIDs , id => {                 const att = v [ `repeating_skills_ ${ id } _skillattribute` ];                 const base = parseInt ( v [ `repeating_skills_ ${ id } _skillattribute` ]) || 0 ;                 let skill = 0 ;                 if ( base > 0 ){                     skill = base                 } else {                     if ( att == "dexterity" ){                         skill = dex * 2                     }                     else if ( att == "insight" ){                         skill = ins * 2                     }                     else if ( att == "empathy" ){                         skill = emp * 2                     }                 }                 updateSkills [ `repeating_skills_ ${ id } _skilldie` ] = skill ;             });             setAttrs ( updateSkills ,{ silent : true });         });     }); }); If not I'd be even more interested to take a look at your HTML and CSS to see what's going on under the hood.  ;)
This is what I have: HTML CSS Which also relies on a rollable table called SuccessDice: Result Weight -3 1 -2 2 -1 4 0 6 1 4 2 2 3 1
1658182845
GiGs
Pro
Sheet Author
API Scripter
John D. said: On the matter of case, I'm foggy on the details but it may just be that repeating section attributes are evaluated in lowercase.  Regardless, the only thing I've ever ran into that required original case is in the creation and application of section IDs.  Such as when programmatically creating repeating sections.  Since attributes are evaluated in lowercase, as a best practice, all attributes should be handled in lowercase.  If camelCase is what you're used to, consider using underscores instead.  Variable names are fine in camelCase, it's the actual HTML sheet attributes in question here. I want to clear something up here: Roll20 does have some idiosyncrcies when it comes to case, but I was not talking about repeating sections. The event line (that line that begins on( ) has a different requirement to every other line of the sheet worker. all attributes, whether repeating or otherwise, must be in lower-case in that line. Cances are you can ignore this, and get away with it for a while, but sooner or later you'll find that change:stat isn't detecting a change in an attribute, because it's not recognising the attribute. People overlook this because it's inconsistent - sometimes it works, sometimes it doesn't. There used to be a much stronger warning about this in the documentation in the wiki, directly from the devs, but at some point the sheetworker documentation was changed and that warning was removed. The warning is still valid: you absolutely must avoid using any upper case laters in that line, for any and all attributes.
1658189574

Edited 1658189622
Thanks for the heads up. I have had problems with this in repeating sections, but I have never encountered an issue outside of a repeating section. With all the snippets that I snatched that had capitals in them, I assumed it was fine. I try to avoid underscores because they seem to mess with repeating section buttons.
1658191014
GiGs
Pro
Sheet Author
API Scripter
Underscores are fine in most cases, are you referring to action buttons (not roll buttons)? They can cause issues there. Action buttons can be finicky.
Yeah, action buttons in repeating sections don't seem to work with underscores.
1658196751
GiGs
Pro
Sheet Author
API Scripter
Yes, in the same way ypou shouldn't have more than one underscore in repeating_ names, you need to avoid underscores in action buttons in repeating sections. That seems to be a bug, because its not officially documented as far as I remember. That's a separate issue to the lower case in the event line I mentioned above, which isn't a bug, just irritating.