I noticed a minor glitch in the code above and fixed it. And because I'm a glutton for punishment, I made a universal version of this sheet worker that will work for any number of repeating sections. So CPP, you can use this for both your repeating sections. Purpose: Repeating Sections that set one or more values outside the section So, imagine you have an equipment list, a set of superpowers, different special defences, each with their own repeating sections. You can have only one item from each section active, and when you do, it sets the value of one or more attributes outside the section, so you can use it in button rolls, or combine it with values from different sections, or apply to your raw stats, etc. So, each repeating section functions like a Radio button. You click which one is active, and it deselects any other one that is active, and updates the value of the related attributes outside the repeating section. The worker to achieve this is below. There's a configuration section at the start, which is the only part that needs editing. Leave the rest alone. This is the user-config part: const radio_sections = { items : { checkbox : { field : 'item_check' }, fields : { item_name : { output : 'item_name_output' , default : '-' }, item_type : { output : 'item_type_output' , default : '-' }, item_quality : { output : 'item_quality_output' , default : '0' }, item_notes : { output : 'item_notes_output' , default : '-' }, } }, modifiers : { checkbox : { field : 'mod_check' }, fields : { mod_value : { output : 'mod_output' , default : 0 }, } } }; It is a variable called radio_sections, and it includes several blocks, one for each repeating section. This includes two sections, named items and modifiers . If you want to add any more sections, just copy the enter first section, from the title items to the comma before the next section, modifiers , and paste it in place. Inside each section block there are two parts: checkbox and fields . For checkbox , there's a field property - just put the name of the attribute inside the repeating section that is used to set whether an item is active or not. fields can include multiple rows. These are the attributes you want to copy out of the repeating section, into attributes outside the section. You can enter as few or as many fields as you want - each needs a separate line. The name at the start is the attribute inside the repeating section. It has two properties, output and default. output is the name of the attribute outside the section where you want this value saved. And default is the value that external attribute should have if no item in the section is checked. Additive Fields I've answered questions before where people have wanted a repeating section for special powers, buffs, magic items and the like, where you can have several items selected, and they add the sum of all bonuses. Imagining having a ring that give +2 DEX and +2 STR, and a belt that gave +4 STR and +4 CON. Wearing both you'd have +6 STR, +2 DEX, and +4 CON. Here's a radio_section that would handle that: buffs : { checkbox : { field : 'buff_check' , multiple : true }, fields : { buff_strength : { output : 'strength_mod' , default : 0 }, buff_dexterity : { output : 'dexterity_mod' , default : 0 }, buff_constitution : { output : 'constitution_mod' , default : 0 }, buff_intelligence : { output : 'intelligence_mod' , default : 0 }, buff_wisdom : { output : 'wisdom_mod' , default : 0 }, buff_charisma : { output : 'charisma_mod' , default : 0 },
buff_label : { output : 'label_mod' , default : '', separator: ', ' },
} }, By adding multiple: true to the checkbox row, you create a repeating section where you can select multiple rows, not just one, and any values in those rows are added together before saving to the external attribute. By default it's assumed this is numerical data - numbers that add together. If you add a separator property to the field (as in buff_label above), it is treated as text. This isnt very practical though. It's probably best for very short identifying symbols. The Code With that out of the way, here's the code: const radio_sections = { items : { checkbox : { field : 'item_check' }, fields : { item_name : { output : 'item_name_output' , default : '-' }, item_type : { output : 'item_type_output' , default : '-' }, item_quality : { output : 'item_quality_output' , default : '0' }, item_notes : { output : 'item_notes_output' , default : '-' }, } }, modifiers : { checkbox : { field : 'mod_check' , multiple : true }, fields : { mod_value : { output : 'mod_output' , default : 0 }, mod_name : { output : 'mod_name_output' , default : '' , separator : ', ' }, } }, buffs : { checkbox : { field : 'mod_check' , multiple : true }, fields : { buff_strength : { output : 'strength_mod' , default : 0 }, buff_dexterity : { output : 'dexterity_mod' , default : 0 }, buff_constitution : { output : 'constitution_mod' , default : 0 }, buff_intelligence : { output : 'intelligence_mod' , default : 0 }, buff_wisdom : { output : 'wisdom_mod' , default : 0 }, buff_charisma : { output : 'charisma_mod' , default : 0 }, } }, }; // utility functions to the change lines amd sectionNames const buildChanges = ( section , fields ) => fields . map ( field => `change:repeating_ ${ section } : ${ field } ` ). join ( ' ' ); const sectionName = ( section , id , field ) => `repeating_ ${ section } _ ${ id } _ ${ field } ` ; Object . keys ( radio_sections ). forEach ( section => { on ( ` ${ buildChanges ( section ,[ radio_sections [ section ]. checkbox . field ]) } ${ buildChanges ( section , Object . keys ( radio_sections [ section ]. fields )) } remove:repeating_ ${ section } sheet:opened` , ( event ) => { const rowid = event . sourceAttribute ? event . sourceAttribute . split ( '_' )[ 2 ] : 0 ; // need to end worker if triggered by a worker (probably itself): if ( event . sourceType === 'sheetworker' ) return ; // need to get an array of all row ids in the current section getSectionIDs ( `repeating_ ${ section } ` , idarray => { // build an array of complete attribute names, for each row in the section const fieldnames = []; idarray . forEach ( id => fieldnames . push ( sectionName ( section , id , radio_sections [ section ]. checkbox . field ))); idarray . forEach ( id => Object . keys ( radio_sections [ section ]. fields ). forEach ( key => fieldnames . push ( sectionName ( section , id , key )))); // using that array, we can now use getAttrs to grab their values from the sheet. getAttrs ( fieldnames , values => { //check if this section combines values or uses a single value. const multiple = radio_sections [ section ]. checkbox . hasOwnProperty ( 'multiple' ) ? radio_sections [ section ]. checkbox . multiple : false ; // create a holding attribute, which will hold all the values of attributes we will change on the sheet const output = {}; // reset the values to '', in case none of the rows are checked Object . keys ( radio_sections [ section ]. fields ). forEach ( key => output [ radio_sections [ section ]. fields [ key ]. output ] = radio_sections [ section ]. fields [ key ]. default ); // loop through each row in the section (using the row ids) idarray . forEach ( id => { // if the row is checked, need to do something with it. const check = parseInt ( values [ sectionName ( section , id , radio_sections [ section ]. checkbox . field )]) || 0 ; if ( check ) { // if its not multiple, dont need to check it matches rowid. // we need to check if the id matches the one just clicked by the player if (! multiple && ( rowid === id || rowid === 0 )) { // if the row IS checked, we need to grab the die value and overwrite the attribute outside the repeating section Object . keys ( radio_sections [ section ]. fields ). forEach ( key => output [ radio_sections [ section ]. fields [ key ]. output ] = values [ sectionName ( section , id , key )]); } else if (! multiple ) { // we're in a row that is not the one the player just clicked, so make sure the check is set to 0 // (to make the section act like a radio button) output [ sectionName ( section , id , radio_sections [ section ]. checkbox . field )] = 0 ; } else { // if multiple, need to add the values together. Object . keys ( radio_sections [ section ]. fields ). forEach ( key => { const out = radio_sections [ section ]. fields [ key ]. output ; const separator = radio_sections [ section ]. fields [ key ]. hasOwnProperty ( 'separator' ) ? radio_sections [ section ]. fields [ key ]. separator : '' ; output [ out ] = radio_sections [ section ]. fields [ key ]. hasOwnProperty ( 'separator' ) ? output [ out ] + ( output [ out ]. length ? separator : '' ) + values [ sectionName ( section , id , key )] : + output [ out ] + (+ values [ sectionName ( section , id , key )]|| 0 ); }); } } });
// we have now looped through every row of the section, so lets update the character sheet. setAttrs ( output ); }); }); }); });