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

Sheetworker for setting values in repeating sections

I have some number attrs that, when equal to 0, won't trigger things that refer to them when the sheet is opened. They are somehow counted as null until something else in the sheet is changed at which point they suddenly start registering as equal to 0. I've fixed this problem for most instances by using a sheetworker triggered by sheet:opened,  but can't get it to work for repeating sections. Is there an issue with my code, or is it just not possible? on('sheet:opened',function(){     getAttrs(['repeating_pc4_pcproj4'], function(values) {         const repeating_pc4_pcproj4new = +values.repeating_pc4_pcproj4 || 0;         setAttrs({             "repeating_pc4_pcproj4":  Math.max( (+v.repeating_pc4_pcproj4new || 0) , (0) )         });    }); });
1646578181
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
You need to get the specific repeating attributes (including the rowid) in order to get the values with getAttrs. You'll need to wrap you getAttrs inside the getSectionIDs sheetworker finction
1646591409
GiGs
Pro
Sheet Author
API Scripter
There are two syntaxes for getting repeating section attributes. The form you have used, repeating_pc4_pcproj4 is the per-row syntax. For this to work, it must be triggered within a row of a repeating section, and roll20 automatically inserts a row id into the attribute name, so it becomes something like repeating_pc4_-ghty6453bcg_pcproj4 Such events can only work for a single row at a time, and are incompatible with the sheet:opened event. If you want something to affect every row of a repeating section (as with sheet:opened), your worker has to build the complete address for every row in the section, and that's where getSectionIDs comes in. So a worker to do this would look something like: on ( 'sheet:opened' , function (){             getSectionIDs ( 'repeating_pc4' , function ( id_array ) {                 // the next line builds an array of attribute names, for the entire section. Don't worry about how it works.                 const rows = id_array . reduce (( all_rows , id ) => [... all_rows , `repeating_pc4_ ${ id } _pcproj4` ], []);                 getAttrs ( rows , function ( values ) {                     // the values object contains all the row attribute names and their values.                     //create an empty object variable to hold the values                     const output = {};                     // loop throw the rows array                     rows . forEach ( function ( row ) {                         // with each row, grab its value                         const score = + v [ row ] || 0 ;                         //check if its below zero annd update it if so                         if ( score < 0 ) {                             // if it's below zero, save the updated value to output                             output [ row ] = 0 ;                         }                         //if  output has values, save to the sheet.                         if ( Object . keys ( output ). length ) {                             setAttrs ( output );                         }                     });                 });             });         }); However... The function you are doing here - check if a value is below zero and set to 0 if so, should not be done like this. It should be done in a response to the attribute change event. If you are using this value anywhere, you'd use it in that code. But if not, you can use your per-use syntax, like so:      on ( 'change:repeating_pc4_pcproj4' , function () {             getAttrs ([ 'repeating_pc4_pcproj4' ], function ( values ) {                 const score = + values . repeating_pc4_pcproj4 || 0 ;                 if ( score < 0 ) {                     // if it's below zero, save the updated value to output                     setAttrs ({                         repeating_pc4_pcproj4 : 0                     });                 }             });         }); This checks the attribute value every time it is changed, and resets its value to 0 if below that. The setAttrs function only runs when the attribute is zero, and the whole function only runs when a specific row attribute is changed. This way there is no lag time: if you tie the check to sheet:opened means that characters may have attributes that show a wrong value, until the sheet is closed and opened again. This avoids that.
Thanks GiGs, that looks really helpful but I've not been clear enough about the purpose. This isn't to correct values that are less than 0, this is to provide values where there aren't any. repeating_pc4_pcproj4  is a number input with a min of 0 and max of 3. There are other elements that are affected by the value, which is fine if a value has been entered. However, if no value has been set it does not behave like a 0 until something in the fieldset's row is changed (itself is hidden and controlled by other elements). So the user creates a new row and  repeating_pc4_pcproj4  doesn't do its thing. Then they enter something in a text input in the new row and suddenly it does the thing it does for being equal to 0. But next time they open the sheet it goes back to not being a number and not triggering the other things. Is there a sheetworker trigger associated with the creation of a new row in a repeating section? If so then I could just use that to set the value of  repeating_pc4_pcproj4  to 0 as soon as it comes into existence.
So basically, the following sheetworker solves the problem once the user enters something in repeating_pc4_pcprojname4, but it would be nicer if the value of repeating_pc4_pcproj4 could be set to 0 before they do so. on('change:repeating_pc4:pcprojname4', () => { getAttrs(['repeating_pc4_pcproj4'], function(values) {         const repeating_pc4_pcproj4new = +values.repeating_pc4_pcproj4 || 0; setAttrs({ "repeating_pc4_pcproj4": Math.max(repeating_pc4_pcproj4new , 0) }) }) });
1646665315

Edited 1646710057
GiGs
Pro
Sheet Author
API Scripter
I see. Any input, textarea, etc, can be given a default value, so it has a value the instant that row is created. Just add value="0" (or whaevever you want the default value to be), like so <input type="number" name="attr_example" value="0"> Checkboxes have a value of 0 automatically, and for selects, just add selected next to one of the option values.
GiGs said: I see. Any input, textarea, etc, can be given a default value, so it has a value the instant that row is created. Just add value="0" (or whaevever you want the default value to be), like so <input type="number" name="attr_example" value="0"> Checkboxes have a value of 0 automatically, and for selects, just add selected next to one of the option values. Already thought of that, but it doesn't make the sheet auto-populate the field when opened. It comes up blank but as soon as I enter something in any other field in the repeating section it then populates the default value, but if I refresh the window and open the sheet again it will be back to empty. If I were to manually set the field to something, even 0, then it will remember from then on. I think this is related to something you told me about a while ago, about how there's a two-way communication between the sheet and the code (or something) and when the sheet is opened it doesn't get told certain things until it communicates back to the source and then receives a response. Or something like that, it was rather technical!
1646750715
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
This sounds like there's an error in the html to me. Can you share that?