Russian Dolls

We have seen how you can output to a separate input, which is then watched for changes. What if you want to output to a single attribute and avoid that intermediate step?

The traditional way to do that is covered here. It’s simple but complicated. (Ah the joy of coding.)

Tweaks to the HTML

To be clear, we are not using this HTML:

<div class="totals">
   <h3>Cost</h3>
   <span>Weapons Total</span>
   <input type="number" name="attr_weapons_cost" value="0">
   <span>Gear Total</span>
   <input type="number" name="attr_gear_cost" value="0">
   <span>Overall Total</span>
   <input type="number" name="attr_total_cost" value="0">
</div>Code language: HTML, XML (xml)

Instead we are trimming it down, to just use this:

<div class="totals">
   <h3>Totals</h3>
   <span>Total Weight</span>
   <input type="number" name="attr_weight" value="0">
   <span>Total Cost</span>
   <input type="number" name="attr_cost" value="0">
</div>Code language: HTML, XML (xml)

The first two inputs are just intermediate steps, and we won’t need them here.

The rest of the HTML and CSS from the introduction post is still used.

The Sheet Worker

So we want to total the two repeating sections at once. You need to watch both repeating sections like this:

on('change:repeating_gear:weight change:repeating_gear:cost change:repeating_weapons:weight change:repeating_weapons:cost', () => {   Code language: JavaScript (javascript)

The traditional way to do that s nest them inside each other, like this:

getSectionIDs('repeating_gear', ids_gear => {
     const fields = [];
     ids_gear.forEach(id => fields.push(section_name('gear', id, 'weight'), section_name('gear', id, 'cost')));
     getSectionIDs('repeating_weapons', ids_weapons => {
        ids_weapons.forEach(id => fields.push(section_name('weapons', id, 'weight'), section_name('weapons', id, 'cost')));   Code language: JavaScript (javascript)

See how both getSectionIDs are present. Since they are asynchronous functions they are unaware of each other, unless nested inside each other.

The fields variable here is created under the first getSectionIDs, and the seocnd one just adds new items to it Also the original ids variable is here changed to ids_gear and ids_weapons. Each section has its own rows and row ids, and we might want to loop through both of them again later, so use different variable names. Much of the rest of the code is the same.

getAttrs(fields, values => {
  const output = {};
  output.weight = 0;
  output.cost = 0;
  ids_weapons.forEach(id => {
     output.weight += num(v[section_name('weapons', id, 'weight')]);
     output.cost += num(v[section_name('weapons', id, 'cost')]);
  });
  ids_gear.forEach(id => {
     output.weight += num(v[section_name('gear', id, 'weight')]);
     output.cost += num(v[section_name('gear', id, 'cost')]);
  });
  setAttrs(output);
}); Code language: JavaScript (javascript)

The Full Worker

Putting it all together, that looks like:

on('change:repeating_gear:weight change:repeating_gear:cost change:repeating_weapons:weight change:repeating_weapons:cost', () => {
    getSectionIDs('repeating_gear', ids_gear => {
        const fields = [];
        ids_gear.forEach(id => fields.push(section_name('gear', id, 'weight'), section_name('gear', id, 'cost'))); 
        getSectionIDs('repeating_weapons', ids_weapons => {
            ids_weapons.forEach(id => fields.push(section_name('weapons', id, 'weight'), section_name('weapons', id, 'cost')));
            getAttrs(fields, values => {
                const output = {};
                output.weight = 0;
                output.cost = 0;
                ids_weapons.forEach(id => {
                  output.weight += num(v[section_name('weapons', id, 'weight')]);
                  output.cost += num(v[section_name('weapons', id, 'cost')]);
                });
                ids_gear.forEach(id => {
                  output.weight += num(v[section_name('gear', id, 'weight')]);
                  output.cost += num(v[section_name('gear', id, 'cost')]);
                });
                setAttrs(output);
            });
    });
});Code language: JavaScript (javascript)

Don’t forget all the closure – these things });.

Conclusion

The code is pretty similar to what we have used before, it’s just repeated for each section. If you need more sections, just nest each inside the first one, and remember to change each ids variable.

One of the last workers I built this way had I think 7 nested repeating sections, which gets out of hand fast. Here’s the basic layout for five of them:

getSectionIDs('repeating_one', ids_one => {
  getSectionIDs('repeating_two', ids_two => {
    getSectionIDs('repeating_three', ids_three => {
      getSectionIDs('repeating_four', ids_four => {
        getSectionIDs('repeating_five', ids_five => {
           getAttrs([...a_bunch_of_arrays], values => {
              <!-- your code here -->
           });
        });
      });
    });
  });  
});Code language: JavaScript (javascript)

So while that can be laborious and clunky in appearance, it does work and work well. But we’ll cover the method I use today in the last post in this sub-series.

Leave a Reply

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