repeatingSum

If you dont want to write the code yourself, you can use my repeatingSum function. I wrote it for exacly the problem we are covering here – adding attributes across entire repeating sections.

Simply drop in the repeatingSum Function along with your helpers, like so:

<script type="text/worker">
   const int = (score fallback = 0) => parseInt(score) || fallback;
   const num = (score fallback = 0) => +score || fallback;
   const section_name = (section, row, field) =>
      `repeating_${section}_${row}_${field}`;

/* ===== REPEATINGSUM ==========
   destinations = the name of the attribute that stores the total quantity
        can be a single attribute, or an array: ['total_cost', 'total_weight']
        If more than one, the matching fields must be in the same order. 
   section = name of repeating fieldset, without the repeating_
   fields = the name of the attribute field to be summed
         destination and fields both can be a single attribute: 'weight'
         or an array of attributes: ['weight','number','equipped']
*/
const repeatingSum = (destinations, section, fields) => {
    if (!Array.isArray(destinations)) destinations = [destinations.replace(/\s/g, '').split(',')];
    if (!Array.isArray(fields)) fields = [fields.replace(/\s/g, '').split(',')];
    getSectionIDs(`repeating_${section}`, idArray => {
        const attrArray = idArray.reduce((m, id) => [...m, ...(fields.map(field => `repeating_${section}_${id}_${field}`))], []);
        getAttrs([...attrArray], v => {
            const getValue = (section, id, field) => v[`repeating_${section}_${id}_${field}`] === 'on' ? 1 : parseFloat(v[`repeating_${section}_${id}_${field}`]) || 0;
            const commonMultipliers = (fields.length <= destinations.length) ? [] : fields.splice(destinations.length, fields.length - destinations.length);
            const output = {};
            destinations.forEach((destination, index) => {
                output[destination] = idArray.reduce((total, id) => total + getValue(section, id, fields[index]) * commonMultipliers.reduce((subtotal, mult) => subtotal * getValue(section, id, mult), 1), 0);
            });
            setAttrs(output);
        }); 
    }); 
};

// end of Helper Functions. all of our sheet workers go after this.

</script>Code language: JavaScript (javascript)

The code in the above section should not altered in any way. Now we create the individual sheet workers.

The Actual Workers

// the repeatingSum workers are very short
on(`change:repeating_weapons:weight change:repeating_weapons:cost`, () => {
    repeatingSum("weapons_weight", section, "weight");     
    repeatingSum("weapons_cost", section, "cost");     
});
on(`change:repeating_gear:weight change:repeating_gear:cost`, () => {
    repeatingSum("gear_weight", section, "weight");     
    repeatingSum("gear_cost", section, "cost");     
});

// the workers to add up the totals attribute look more familiar.
on(`change:weapons_weight change:gear_weight', () => {
   getAttrs(['weapons_weight', 'gear_weight'], values => {
      const weapons = num(v['weapons_weight']);
      const gear = num(v['gear_weight']);
      const total = weapons + gear;
      setAttrs({
         total_weight: total
      });
   });
});
on(`change:weapons_cost change:gear_cost', () => {
   getAttrs(['weapons_cost', 'gear_cost'], values => {
      const weapons = num(v['weapons_cost']);
      const gear = num(v['gear_cost']);
      const total = weapons + gear;
      setAttrs({
         total_weight: total
      });
   });
});
Code language: JavaScript (javascript)

As in the last post, we can streamline these workers with Universal Sheet Workers.

const sections = ['weapons', 'gear'];
sections.forEach(section => {
   on(`change:repeating_${section}:weight change:repeating_${section}:cost`, () => {
       repeatingSum(`${section}_weight`, section, "weight");     
       repeatingSum(`${section}_cost`, section, "cost");     
   });
});

const totals = ['weight', 'cost'];
totals.forEach(total => {
   on(`change:weapons_${total} change:gear_${total}`, () => {
      getAttrs([`weapons_${total}`, `gear_${total}`], values => {
         const weapons = num(v[`weapons_${total}`]);
         const gear = num(v[`gear_${total}`]);
         const total = weapons + gear;
         setAttrs({
            total_weight: total
         });
      });
   });
});
Code language: JavaScript (javascript)

A Caution

This method is very inefficient. Each repeatingSum contains a getSectionIDs, getAttrs, and setAttrs, and there are four of them here (weight and cost for each of weapons and gear).

It is very simple to write. By all means use it of writing the code yourself is tricky – that’s what it was meant for. But you should stop using it if you can write the code yourself.

But again, don’t worry too much. Most repeating sections don’t cause a lot of cascades so their hit on sheet efficiency is usually low. Don’t let perfect be the enemy of good.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.