You cant do it quite like that. One way is to use two sheet workers. First, for the internal changes. When bodyPercent changes, you dont need sectionIds, you can just update that row alone: on("change:repeating_body:bodypercent sheet:opened", function () {
getAttrs(["endTot", "repeating_body_bodyPercent"], function (value) {
let endTotal = parseInt(value.endTot, 10) || 0;
let rowsPercent = parseInt(value.repeating_body_bodyPercent, 10) ||0;
let rowsTotalPercent = Math.round((rowsPercent/100)*endTotal);
setAttrs({repeating_body_bodySegEndTot: rowsTotalPercent});
});
}); When endTot changes, you need to change every row, and in this case you need to do getSectionIds before getAttrs. I''l write this script twice, first the more easily understandable way, and the second the more compact way. In case you're not familiar, any text starting with // is a comment and is ignored by roll20. You can delete them when you understand whats happening. on("change:endtot sheet:opened", function () { getSectionIDs("repeating_body", function (idarray) { // first we need to get an array of all the relevant row names, so you can getAttrs them const fieldNames = []; for (let i = 0; i < idarray.length; i++) { fieldNames.push('repeating_body_' + idarray[i] + '_bodyPercent'); }
// now need to get the attribute values, along with endTotal. concat allows us to join two arrays. // putting [ ] around endtotal treats it as an array so concat can be used with it. getAttrs(fieldNames.concat(["endTot"]), function (values) { const endTotal = parseInt(value.endTot, 10) || 0;
// lets name the variable for setAttrs something unambigious so it can be confused with anything else: const output = {};
for (let i = 0; i < idarray.length; i++) { // now need to calculate the value. Use variable names that describe what the value actually is. const thisRowsPercentValue = parseInt(values['repeating_body_' + idarray[i] + '_bodyPercent'],10) ||0; const EndMultipliedByPercent = Math.round((thisRowsPercentValue/100) * endTotal); output['repeating_body_' + idarray[i] + '_bodySegEndTot'] = EndMultipliedByPercent; } if(output) setAttrs(output); }); }); }); Note, i used const in place of let, just because we can. const is for variables that dont change, once created. Let is for variables you intend to modify. Both const and let create variables that only exist within the scope. For instance, in that last for loop, each time the loop was entered, a new thisRowsPercentvalue variable was created, and when the end of that loop was reached, it was discarded. So, the above is one way to do it. Here's a bit more compact version that uses some more advanced techniques. on("change:endtot sheet:opened", function () { getSectionIDs("repeating_body", function (idArray) {
// map is a way to essentially loop through an array, as a single operation. Here it replaces the first for loop above.
const fieldNames = idArray.map(id => `repeating_body_${id}_bodyPercent`);
// it takes every item in the array (id being the current row id),
// and performs a conversion on it, and saves the converted items into a new array.
// by the way: `repeating_body_${id}_bodyPercent` is the same as 'repeating_body_' + id + '_bodyPercent'
// This is called a string literal and gets very handy when strings get more complicated.
// the way of writign strings that you're more familiar with would work fine too.
getAttrs([...fieldNames, "endTot"], function (values) { // when putting three dots ... before an arrays name, it expands that array into individual elements - so here we
// avoid the need to use concat. This ... is called the spread operator. const endTotal = parseInt(value.endTot, 10) || 0; const output = {};
// the forEach function is a very useful alternative to using for loops.
// instead of having to use i and get array[i] for the value
// it loops through the values directly. In the below forEach, each turn through the loop,
// field is set to the next instance of repeating_body_${id}_bodyPercent (with id filled in already of course) fieldNames.forEach( field => { const thisRowsPercentValue = parseInt(values[field],10) ||0; const EndMultipliedByPercent = Math.round((thisRowsPercentValue/100) * endTotal); output[`repeating_body_${id}_bodySegEndTot`] = EndMultipliedByPercent; }); if(output) setAttrs(output); }); }); });