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

repeating sections, buttons, and a single sheet worker

I have a few repeating sections to help organize inventory. <fieldset class="repeating_inventorycombat"> <input name="attr_inventoryslots"/><button type="action" name="act_usage">Use</button> </fieldset> <fieldset class="repeating_inventoryconsumables> <input name="attr_inventoryslots"/><button type="action" name="act_usage">Use</button> </fieldset>   The Use button should get the value of " inventoryslots" on the relevant line and do some stuff with it. I could write a different sheet worker for each section (which are otherwise identical), but I'd prefer to have them all the same. I've gotten as far as being able to identify which button was clicked, but I can't seem to get the inventoryslots value. on('clicked:repeating_inventorycombat:usage clicked:repeating_inventoryconsumable:usage clicked:repeating_inventorygeneral:usage clicked:repeating_inventorycarriedloot:usage clicked:repeating_inventoryephemera:usage clicked:repeating_inventorystored:usage', (eventInfo) => {     const trigger = eventInfo.sourceAttribute.split('_');     const list = trigger[1]     const rowid = trigger[2]     const item ='repeating_'+list+'_'+rowid+'_inventoryslots' setAttrs({ testfield1: (eventInfo.sourceAttribute),                 testfield2: item }); });         How do I use the variable "item" get get the actual value? I tried  getAttrs([`$(item)`], function(values) { and              testfield2: `values.${item}` but testfield2 shows the item string ( repeating_inventorycombat_somerowid_usage ) rather than value of the variable  (a value like  3 ) . I feel like I'm close, but can't quite cross the finish line. If I can sort this, I have 2 or 3 use cases to tighten up this character sheet. Thanks!
1718836801

Edited 1718836943
GiGs
Pro
Sheet Author
API Scripter
I can see two ways to proceed. The first is the method you re currently using: put all the section names together and use eventInfo to figure out which is being triggered, and the second is what I used to call a Universal SheetWorker - create an array of the repeating section names, and use forEachto loop through them - so you have multiple sheet workers but it looks like just one and is easy to code. I'm unlear on what you areactually trying to do. Wouldn't testfield1 and 2 vary depending on the repeating section being triggered? Please state exactly what you are doing, and we can tell you how to do it, and whether you need to use getSectionIDs. (You probably do.) For your specific question, you an probably put getAttrs imediately after this line const item ='repeating_'+list+'_'+rowid+'_inventoryslots' like const item ='repeating_'+list+'_'+rowid+'_inventoryslots'; getAttrs([item], function(values) { For testfield2, you are jyst creating a string. To actually get the value, you need something more like testfield2: values[item] When grabbing something from the values object (which is a Javascript object, there re two syntaxes you can use. You use the dot syntax whenever you know the name exactly, and it;s not dynamic, like testfield2: values.item (This would only work for an attribute called item.) When the item is a variable, you must use the squarebracket syntax like testfield2: values[item] Personally, I'd put the values part before setAttrs and create a variable, like const my_item = values[item]; setAttrs({ testfield2: my_item }); That's a little more writig, but makes it easier to examne the value in the console if you need to, like const my_item = values[item]; console.log({my_item}); setAttrs({ testfield2: my_item });
1718836880
GiGs
Pro
Sheet Author
API Scripter
I predict you are going to have problems with testfield1 and 2, because they'll be overwritten when you click the button in any repeating section. But maybe that's intended.
Thanks for the syntax correction! I can see the variable being set in the console, but the sheet only updates when it is reloaded (with the last button clicked); luckily testfield1 and 2 are just for testing and the actual value is going to get passed into some custom dice parsing.
Sample full repeating section (one of 6): <fieldset class="repeating_inventorycombat">   <input style="width: 190px;" type="text" name="attr_inventoryItemName"/>   <input style="width: 35px;text-align: center;"type="text" value=1 name="attr_inventoryslots"/>   <select name="attr_inventoryUsage" style="width: 58px;"><option value="0">na</option><option value="dep">dep</option><option value="4">d4</option><option selected="selected" value="6">d6</option><option value="8">d8</option><option value="10">d10</option><option value="12">d12</option></select><button type="action" name="act_usagepro">Use</button>     <input type="checkbox" title ="click to expand and add more details" class="sheet-gearnotes">   <div class="sheet-bar">     <table width=100%>       <tr><td style="padding: 5px;text-align: right;">         <input type="checkbox" name="attr_inventoryItemgroup"/> Goup Item?            <input type="checkbox" name="attr_inventoryItemfragile"/> Fragile?            <input type="checkbox" name="attr_inventoryItemunstable"/> Unstable?       </td></tr>       <tr><td style="padding: 5px;text-align: right;">         <input type="text" style="width: 300px;" name="attr_action" placeholder="action text">       </td></tr>       <tr><td style="padding: 5px;text-align: right;">         <input type="text" style="width: 300px;" name="attr_notes" placeholder="notes"></td></tr>     </table>   </div> </fieldset> final sheetworker code: on('clicked:repeating_inventorycombat:usagepro clicked:repeating_inventoryconsumable:usagepro clicked:repeating_inventorygeneral:usagepro clicked:repeating_inventorycarriedloot:usagepro clicked:repeating_inventoryephemera:usagepro clicked:repeating_inventorystored:usagepro', (eventInfo) => {     const trigger = eventInfo.sourceAttribute.split('_');     const list = trigger[1]     const rowid = trigger[2]     const itemnam ='repeating_'+list+'_'+rowid+'_inventoryItemName'     const itemuse ='repeating_'+list+'_'+rowid+'_inventoryUsage'     const itemtxt ='repeating_'+list+'_'+rowid+'_action'     getAttrs([itemnam, itemuse, itemtxt], function(values) {         const nameid = values[itemnam]         const usageid = values[itemuse]         const actions = values[itemtxt]         const roll = (Math.ceil(Math.random() * usageid));         console.log({nameid});         console.log({usageid});         console.log({actions});         let result = '';         let newdie = '';         let red = '';     if (roll > 2){             result = 0;             newdie = usageid;         }else{             result = 1             newdie = (usageid -2);             if(usageid === '12'){red = '10'}             if(usageid === '10'){red = '8'}             if(usageid === '8'){red = '6'}             if(usageid === '6'){red = '4'}             if(usageid === '4'){red = 'dep'}             setAttrs({                 [itemuse]: red             });         }     var roll_text = `&{template:BXDHuse}{{name=@{character_name}}}{{action=USAGE CHECK}}{{detail=${nameid}}}{{result=[[${result}]]}}{{roll=${roll}}}{{basedie=${usageid}}}{{newval=[[${newdie}]]}}{{text=${actions}}}`;     startRoll(roll_text, (results) => {             finishRoll(results.rollId, {});     });     }); }); For each item in each of the repeating sections the use button "rolls" a die based on the '_inventoryUsage' value of that line. If the roll is a 1 or 2, it drops the usage by 1 die type (or to depleted if a d4) and calls a roll template (a placeholder at the moment)  to display everything.
1718905515

Edited 1719014661
GiGs
Pro
Sheet Author
API Scripter
One thing that leaps out at me. I would change that if statement in one of two wyas. First, add lots of else statements: if(usageid === '12'){red = '10'} else if(usageid === '10'){red = '8'} else if(usageid === '8'){red = '6'} else if(usageid === '6'){red = '4'} else if(usageid === '4'){red = 'dep'} That means each if statement isn't checked - as soon as one is found to be true, the rest are ignored. Alternatively, there's a pattern there to be exploited red = (usageid > 4) ? (Number(useageid) -2) : 'dep'; The brackets are there for reading convenience. The code doesn't need them.
1718905572
GiGs
Pro
Sheet Author
API Scripter
Is your HTML and sheet worker complete, or is there something you still need help with?
1718905966

Edited 1719014888
GiGs
Pro
Sheet Author
API Scripter
By the way, I mentioned earlier about putting the repeating sections in an array, you might still want to do that. Instead of this line: on('clicked:repeating_inventorycombat:usage clicked:repeating_inventoryconsumable:usage clicked:repeating_inventorygeneral:usage clicked:repeating_inventorycarriedloot:usage clicked:repeating_inventoryephemera:usage clicked:repeating_inventorystored:usage', (eventInfo) => { You could have const inventory_sections = 'combat', 'consumable', 'general', 'carriedloot', 'ephemera', 'stored']; on(inventory_sections.map(w => `clicked:repeating_inventory${w}`).join(' '), eventInfo => { That makes it easy to add new inventory sections if you ever plan to. map is a function that does something with each item in an array, and join is a function that turns an array into a string, using the listed separator between each item.
I'm all set and everything works, but i'll likely impliment those two other changes; the improved 'red=' statement is fantastic.  I'm using the array method for a load of other things but couldn't quite sort the syntax to do what you presented.  Again - thank you!  You are an invaluable resource for this community, GiGs!
1719014696
GiGs
Pro
Sheet Author
API Scripter
Duck said: You are an invaluable resource for this community, GiGs! It's lovely to hear something like that just before bed. Thanks!