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 .
×
We’re currently investigating an issue that may cause higher-resolution images to fail to load.
Create a free account

Calling a repeating section value outside of it

1691373706

Edited 1691373758
As the title says, i am trying to reference a value inside a repeating section outside of it but cannot seem to make it work. I'll really appreciate some help, this is the code: < button type = "roll"             value = "&{template:default}             {{name= DMG}}             {{Resultado= [[@{repeating_damage-damage_dice_amount}@{repeating_damage-damage_dice}]]}}"         > DMG </ button >         < fieldset class = "repeating_damage" >             < input type = "number" name = "attr_damage_dice_amount" value = "1" >             < select name = "attr_damage_dice" >                 < option value = "d4" selected > d4 </ option >                 < option value = "d6" > d6 </ option >                 < option value = "d8" > d8 </ option >                 < option value = "d10" > d10 </ option >                 < option value = "d12" > d12 </ option >                 < option value = "d20" > d20 </ option >             </ select >         </ fieldset >
1691376058
GiGs
Pro
Sheet Author
API Scripter
You'll need to get the value wtith a sheet worker. You are very close to a syntax you can only use inside a repeatign section: {{Resultado= [[@{repeating_damage_damage_dice_amount}@{repeating_damage_damage_dice}]]}}" Notice the underscore instead of a dash. Unfortunately this won't work outside of a repeating section, and you'll understand why soon. Imagine - a repeating section can have any number of rows, from 0 to a 100 or higher. When roll20 tries to acess a value, it needs to know which row to get the value from. When you're inside a section and use the syntax above, roll20 supplies the current row ID, the row that the code is on. That's why it works there. So, if you want a button like that, the two easiest solutions are: put it in the repeating section, so it knows which row its on. In the repeating section, have someway of saving a value to an input outside the repeating section, which your button then uses instead of the repeating section.
1691421623
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
GiGs has the right of it. The only correction I'd make is that the repeating macro syntax doesn't actually use the repeating_<section name>_ prepend.
1691432627
GiGs
Pro
Sheet Author
API Scripter
Oh yes, good point. I have had my head too deep into sheet workers lately.
1691436030
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Heh, I do the same thing when I've been working on sheetworkers a lot and suddenly have to build just a basic roll button.
Thank you both for your help! I see... It's a bit more complex than I thought, or maybe I am overthinking. I need to get to store the value in an array basically and then read the array and replace it or add over it.. right? This is what i was thinking but maybe I am being silly:     var damageValues = {};     on("sheet:opened change:repeating_damage", function(eventInfo) {         getSectionIDs("repeating_damage", function(ids) {             // Loop through each repeating section instance             ids.forEach(function(id) {                 // Get the values of the fields for the current instance                 getAttrs(["repeating_damage_" + id + "_dice", "repeating_damage_" + id + "_dice_amount"], function(values) {                     var damageAmount = parseInt(values["repeating_damage_" + id + "_dice_amount"]) || 0;                     var damageDice = parseInt(values["repeating_damage_" + id + "_dice"]) || 0;                     var totalDamage = damageAmount + damageDice;                     setAttrs({                         "attack_damage"[id]: totalDamage[id]                     });                 });             });         });     });
1691458062
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
You're close MaRiTg. The big issue with how you're doing it is putting getAttrs and setAttrs inside a loop to run multiple of them at once. This can cause large lag on your sheet. The better way is to get all the repeating attributes in one getAttrs call, and apply all your changes with a single setAttrs. There was also some oddness with how you were doing setAttrs: // You likely don't need the sheet:opened here. Just set the default value for your attribute(s) to what it should be from the start. on("change:repeating_damage", function(eventInfo) { getSectionIDs("repeating_damage", function(ids) { // create an array of the attributes to get for each ID. const getArr = ids.reduce((memo,id) => { memo.push(`repeating_damage_${id}_dice`,`repeating_damage_${id}_dice_amount`); return memo; },[]); // get all the attributes in getArr (aka all the damage info from each rowDamage) getAttrs(getArr,(values) => { const setObj = {}; //Empty object for us to accumulate our changes in // set the attack_damage equal to the total damage all damage rows setObj.attack_damage = ids.reduce((total,id) => { const damageAmount = parseInt(values["repeating_damage_" + id + "_dice_amount"]) || 0; const damageDice = parseInt(values["repeating_damage_" + id + "_dice"]) || 0; const rowDamage = damageAmount + damageDice; return total + rowDamage; },0); // Apply our changes setAttrs(setObj,{silent:true}); //I always use silent:true to avoid cascades of getAttrs/setAttrs which cause lag on sheets }) }); }); Now, this is just my understanding of what you want. If it doesn't do what you want, post back with a plain english description of what sort of total you are trying to get.
1691458689
GiGs
Pro
Sheet Author
API Scripter
I'm not clear about a couple of things in your code. In this post, I'll try to explain the problems. In the next post, I'll start working towards a solution. But first, there's a lot that is correct. For someone's first attempt at a repeating section worker, you've done pretty good. What is damageValues at the start for? It's not used the worker. The syntax for this part is incorrect: setAttrs({ "attack_damage"[id]: totalDamage[id] }); First, this syntax is incorrect and will cause your sheet worker to crash: "attack_damage"[id]: This is also incorrect, for a different reason: totalDamage[id] You dont create an array to enter that value. totalDamage is being created on every turn of the loop, and when it is created, it is a string, not an array. You appear to be trying to store these values in an array, which is possible, but I cant tell where the array is and how values would be extracted from it. Finally, you code makes a classic repeating sections error.  If you can avoid it, don't put getAttrs and setAttrs inside a loop. This isn't something that causes the code to crash, but it can be extremely laggy. getAttrs and setAttrs are functions that must extract or save to roll20's servers. That means each one has to make a connection over the net and wait for a response. But you can bundle up stats in a single getAttrs and setAttrs call, and do it in a fraction of the time. We'll look at how to do that.
1691458926
GiGs
Pro
Sheet Author
API Scripter
I've been ninja'd. But we might lack some information. Where do you want to save the result of the worker. Scott's function assumes you are saving it inside the repeating section and honestly, that's the best and easiest way to do it. You'lll need to move your button inside the repeating section too. This means every row will have its own button.
Yeah I see, sorry if I make some clumpsy mistakes in optimization I have a bit of a hard time grasping the roll20 coding syntax so I am constantly making rookie mistakes xD. Basically this is what I am trying to Achive: As you can see in that section, in the damage section you can select multiple dice values an roll an x amount of dice of each type. That's why setting the damage inside the repeating section is not really a solution since each iteration will just roll the dice asign to it instead of the total amount of dice.
1691461837
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
GiGs said: I've been ninja'd. But we might lack some information. Where do you want to save the result of the worker. Scott's function assumes you are saving it inside the repeating section and honestly, that's the best and easiest way to do it. You'lll need to move your button inside the repeating section too. This means every row will have its own button. Actually, my solution assumes it's stored in a non repeating attribute that totals all the damage in the section. But, since Martig wants it to be an assembly of a dice roll, it'll need some changes (right now it assumes it's calculating a number). This version would concatenate each dice roll into a single roll expression (I'm assuming here that the value of repeating_damage_dice is a number. // You likely don't need the sheet:opened here. Just set the default value for your attribute(s) to what it should be from the start. on("change:repeating_damage", function(eventInfo) { getSectionIDs("repeating_damage", function(ids) { // create an array of the attributes to get for each ID. const getArr = ids.reduce((memo,id) => { memo.push(`repeating_damage_${id}_dice`,`repeating_damage_${id}_dice_amount`); return memo; },[]); // get all the attributes in getArr (aka all the damage info from each rowDamage) getAttrs(getArr,(values) => { const setObj = {}; //Empty object for us to accumulate our changes in // set the attack_damage equal to the total damage all damage rows setObj.attack_damage = ids.reduce((total,id) => { // A string that will be used for concatenating. If total already has content, it becomes a + (to add the dice together). If total doesn't already have content, it becomes an empty string. const addString = total ? ' + ': ''; const damageAmount = values[`repeating_damage_${id}_dice_amount`]; //Since you're working with these as strings, there's really no need to parseInt them. const damageDice = values[`repeating_damage_${id}_dice`]; // I've also swapped your concatenation for template literals. They do the same thing, but are easier to read. // Return the concatenated dice expression. return `${total}${addString}${damageAmount}d${damageDice}`;//If the value of the repeating_damage_dice select options is in the form dY (e.g. d8, d10, etc), then just remove the `d` before `${damageDice}` },''); // Once we've looped through all IDs, we have a complete roll expression. // Apply our changes setAttrs(setObj,{silent:true}); //I always use silent:true to avoid cascades of getAttrs/setAttrs which cause lag on sheets }) }); });
1691462581

Edited 1691462634
Ok, that's perfect. Thank you for the help and the explanation!! I always try to fix things myself but my understanding of repeating section is lacking at best
1691465451

Edited 1691716710
GiGs
Pro
Sheet Author
API Scripter
MaRiTg R. said: Ok, that's perfect. Thank you for the help and the explanation!! I always try to fix things myself but my understanding of repeating section is lacking at best They are pretty complex! I hope Scott will forgive me, but I've rewritten his worker without using the reduce function, so you can (hopefully) see what is happening. You can also compare the two functions, and maybe understand his function better. on ( "change:repeating_damage" , function () {     getSectionIDs ( "repeating_damage" , function ( ids ) {         // create an empty array to contain the attributes         const getArr = [];         // now loop throw the ids array, and add the attribute names to getArr;         ids . forEach ( function ( id ) {             // id is a sapecific row id.             getArr . push ( `repeating_damage_ ${ id } _dice` , `repeating_damage_ ${ id } _dice_amount` );         });                 // get all the attributes in getArr (aka all the damage info from each rowDamage)         getAttrs ( getArr , ( values ) => {             // create an empty array to hold the final output             const attack_array = [] ;             // loop through all the rows in the ids array again, to construct the output;             ids . ForEach ( id => {                 const damageAmount = values [ `repeating_damage_ ${ id } _dice_amount` ]; //Since you're working with these as strings, there's really no need to parseInt them.                 const damageDice = values [ `repeating_damage_ ${ id } _dice` ];                 attack_array . push ( damageAmount + damageDice );             });             // we not have an array of each row's results, but we need a string.             // luckily, javascript has a function to convert arrays into strings, and put a separator between each one.             const attack_string = attack_array . join ( '+' );             // now, finally we want to output the string.             setAttrs ({                 attack_damage : attack_string             } );         });     }); }); Notice how you have two loops, first to construct an array of the attributes for getAttrs (so you only need to run getAttrs once), and a second tiime to do the actual work of building the output. The vast majority of repeating section workers can follow this model. If I were writing the function myself, my version would more closely resemble Scott's. I'm not suggesting this function as an alternative, just showing it for instructional purposes. If that repeating section grows to include more attributes, I'd change the first line of this worker to: on ( "change:repeating_damage:dice_amount change:repeating_damage:dice" , function () { That way its only being triggered by the attributes used in the worker. Also adding {silent:true} in the setAttrs seems very sensible. I tend to rely on the cascading effects of setAttrs, so don't use it as often as I should for maximum efficiency, but it seems perfect here.
I see thank you so much for your help!! I'll learn from this, and hopefully won't have to ask much when I build the spell section :P