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

Sheet Worker changing repeating fields

1588027169
MAMS Gaming
Pro
Sheet Author
I'm trying to get a button outside of the repeating field to show/hide a piece of information in all the rows of the repeating field. // Opens and Closes Source inputs on("clicked:source_toggle", function() { // Check the current value of the hidden attribute. getAttrs(["sourcebook"], function(v) { // Toggle the hidden attribute value between "hide" and "show" var sourceflip = v["sourcebook"] !== "hide" ? "hide" : "show" setAttrs({ "sourcebook": sourceflip }); // Toggle the hidden attribute in repeating section as well getSectionIDs("greenabilities", function(idarray) { for(var i=0; i < idarray.length; i++) { setAttrs({ "repeating_greenabilities_" + idarray[i] + "_resourcebook": sourceflip }); } }); }); }); It worked until I tried to put in the repeating section. Once I did, it stopped working outside of the repeating section as well.
1588035644
GiGs
Pro
Sheet Author
API Scripter
Firstly, regarding efficiency: you never want to have more than one setAttrs in a single sheet worker. And never ever put one inside a repeating section. You can avoid it by creating a variable to hold the attributes, and then doing setAttrs on that variable at the end, like so: var output = {}; output['attribute_name'] = attribute_value; output['another_attribute_name'] = another_attribute_value; setAttrs(output); So with that out of the way, here's a version of your sheet worker that should work, with comments: on("clicked:source_toggle", function() {     // first get a list of the full attribute names in the repeating section     getSectionIDs("repeating_greenabilities", function(idarray) {         var fieldnames = [];         for(var i=0; i < idarray.length; i++) {             fieldnames.push(                 "repeating_greenabilities_" + idarray[i] + "_resourcebook"             );         }         // add the non-repeating attribute to the arrau         fieldnames.push("sourcebook");         // you always do the getAttrs after getSectionIDs. Like setAttrs, you want only one getAttrs if possible.         // getAttrs wants an array of names, and fieldnames is an array, so we can just use that         getAttrs(fieldnames, function(v) {             // Check the current value of the hidden attribute.             // Toggle the hidden attribute value between "hide" and "show"             var sourceflip = v["sourcebook"] !== "hide" ? "hide" : "show";                          // create a variable to hold the attributes to be saved to the sheet             var output = {};             // add sourcebook             output["sourcebook"] = sourceFlip;             // now loop through the repeating section, and add the toggeled attributes there                     for(var i=0; i < idarray.length; i++) {                 output["repeating_greenabilities_" + idarray[i] + "_resourcebook"] = sourceflip;             }             // now update the sheet             setAttrs(output);         });     }); }); For completion, here's the script how I would write it, using more modern syntax and functions: on("clicked:source_toggle", () => {     getSectionIDs("repeating_greenabilities", idarray => {         const fieldnames = [];         idarray.forEach(id => fieldnames.push(`repeating_greenabilities_${id}_resourcebook`));         getAttrs([...fieldnames, 'sourcebook'], function(v) {             const sourceflip = v["sourcebook"] !== "hide" ? "hide" : "show";             const output = {};             output["sourcebook"] = sourceFlip;             idarray.forEach(id => output[`repeating_greenabilities_${id}_resourcebook`] = sourceflip);             setAttrs(output);         });     }); });
1588041549
MAMS Gaming
Pro
Sheet Author
That's brilliant. Thank you! I only taught myself html/css/java over these past 2 week in order to write this character sheet. Neither of your codes worked at first. I'm going to assume that you capitalized that F to give me a challenge. Finding it made me analyse, and understand the code better. Thanks again.
1588044539
MAMS Gaming
Pro
Sheet Author
Okay, in an attempt to make sure I only used setAttrs once, I just made this: on("clicked:source_toggle", () => { getSectionIDs("repeating_greenabilities", greenarray => { getSectionIDs("repeating_yellowabilities", yellowarray => { getSectionIDs("repeating_redabilities", redarray => { const fieldnames = []; greenarray.forEach(id => fieldnames.push(`repeating_greenabilities_${id}_resourcebook`)); yellowarray.forEach(id => fieldnames.push(`repeating_yellowabilities_${id}_resourcebook`)); redarray.forEach(id => fieldnames.push(`repeating_redabilities_${id}_resourcebook`)); getAttrs([...fieldnames, 'sourcebook'], function(v) { const sourceflip = v["sourcebook"] !== "hide" ? "hide" : "show"; const output = {}; output["sourcebook"] = sourceflip; greenarray.forEach(id => output[`repeating_greenabilities_${id}_resourcebook`] = sourceflip); yellowarray.forEach(id => output[`repeating_yellowabilities_${id}_resourcebook`] = sourceflip); redarray.forEach(id => output[`repeating_redabilities_${id}_resourcebook`] = sourceflip); setAttrs(output); }); }); }); }); }); and it works. It feels weird to have them nested, but it works. Thanks again for the assist.
1588049898
GiGs
Pro
Sheet Author
API Scripter
MAMS Gaming said: Neither of your codes worked at first. I'm going to assume that you capitalized that F to give me a challenge. Finding it made me analyse, and understand the code better. Yes, that's perfectly accurate. Lol, sorry about that, too much of a habit when writing code to write variable names like that. And your code example: that's excellent. Nesting getSectionIDs is what you have to do there, because of the way roll20 works. You did a great job adapting the code.
1588060932
GiGs
Pro
Sheet Author
API Scripter
PS: i was just grabbing the code for my records, and noticed my code included a harmless error. This line getAttrs([...fieldnames, 'sourcebook'], function(v) { you dont actually need the fieldnames there. the getAttrs functioon grabs attributes from the sheet and stores their values, but you dont read the values of the fieldnames, you overwrite them. So this line can be getAttrs(['sourcebook'], function(v) { The rest should be left as is.
1588064197
Andreas J.
Forum Champion
Sheet Author
Translator
MAMS Gaming said: That's brilliant. Thank you! I only taught myself html/css/java over these past 2 week in order to write this character sheet. I sure how you're talking about Java Script , not Java.
1588084143
MAMS Gaming
Pro
Sheet Author
GiGs said: Yes, that's perfectly accurate. Lol, sorry about that, too much of a habit when writing code to write variable names like that. I got into that habit while writing Lua for TTS, but I could have sworn I read somewhere that there are instances in html that caps messes with (other than first letter). I've learned to avoid _underscores_ during repeating sections, but I couldn't remember where to avoid caps, so i just avoided them in general. Andreas J. said: I sure how you're talking about Java Script , not Java. Yes. I keep shortening JavaScript to Java. That's a habit I need to break. I heard there's another language named Java that is very different.
1588087585

Edited 1588087737
GiGs
Pro
Sheet Author
API Scripter
MAMS Gaming said: GiGs said: Yes, that's perfectly accurate. Lol, sorry about that, too much of a habit when writing code to write variable names like that. I got into that habit while writing Lua for TTS, but I could have sworn I read somewhere that there are instances in html that caps messes with (other than first letter). I've learned to avoid _underscores_ during repeating sections, but I couldn't remember where to avoid caps, so i just avoided them in general. Javascript is fine with caps, generally. In roll20 there's one specific place where caps cause issues: on the event line of sheet workers. This part on('change:attributeName' on the change line, attribute names must be entirely lower case. Everywhere else they are fine - in fact, roll20 is completely case insenstive everywhere else. So if you have an attribute you'd named SourceBook, this would work amusingly: on('change:sourcebook', () => {     getAttrs['SOURCEBOOK'], v => {         var source = v.sOURceBOok;             setAttrs({                     sourceBOOK: source             });        });  }); The above would work fine, because roll20 does not recognise the case of attribute names, but the event line needs all attribute names to be lower cased. So with that same attribute, SourceBook, this would fail: on('change:SourceBook', () => {     getAttrs['SourceBook'], v => {         var source = v.SourceBook;             setAttrs({                     SourceBook: source             });        });  }); More confusingly, it likely would work some of the time, then fail when you least expect it. So avoid lower case on the change line. This is why the wiki recommends using lower case all the time for all attributes. Just to avoid accidents here. If you know what you're doing, you dont have to follow that suggestion, but its pretty good advice. PS: yes Java and Javascript are very different. If you need to shorten it, its best to use JS.
1588450447
MAMS Gaming
Pro
Sheet Author
Wait. If we don't need  fieldnames  in the getAttrs, why do we need it at all? I tried removing those lines of code, and it still seems to work. Am I breaking something that I'm not seeing? on("clicked:source_toggle", () => { getSectionIDs("repeating_greenabilities", greenarray => { getSectionIDs("repeating_yellowabilities", yellowarray => { getSectionIDs("repeating_redabilities", redarray => { getAttrs([...fieldnames, 'sourcebook'], function(v) { const sourceflip = v["sourcebook"] !== "hide" ? "hide" : "show"; const output = {}; output["sourcebook"] = sourceflip; greenarray.forEach(id => output[`repeating_greenabilities_${id}_resourcebook`] = sourceflip); yellowarray.forEach(id => output[`repeating_yellowabilities_${id}_resourcebook`] = sourceflip); redarray.forEach(id => output[`repeating_redabilities_${id}_resourcebook`] = sourceflip); setAttrs(output); }); }); }); }); });
1588450779
GiGs
Pro
Sheet Author
API Scripter
Yes, you're right. I used code that I've written dozens of times, and included it by habit, but it's not needed the way this particular worker is written. So this is fine: on("clicked:source_toggle", () => { getSectionIDs("repeating_greenabilities", greenarray => { getSectionIDs("repeating_yellowabilities", yellowarray => { getSectionIDs("repeating_redabilities", redarray => { getAttrs(['sourcebook'], function(v) { const sourceflip = v["sourcebook"] !== "hide" ? "hide" : "show"; const output = {}; output["sourcebook"] = sourceflip; greenarray.forEach(id => output[`repeating_greenabilities_${id}_resourcebook`] = sourceflip); yellowarray.forEach(id => output[`repeating_yellowabilities_${id}_resourcebook`] = sourceflip); redarray.forEach(id => output[`repeating_redabilities_${id}_resourcebook`] = sourceflip); setAttrs(output); }); }); }); }); }); I removed the fieldnames from the getAttrs line, just to clean it up a bit more.