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 .
×
Create a free account

Referencing multiple repeating fields

Say I have a button that rolls three dice, and each dice is drawn from a different repeating field.  Can I do this?   My initial thought was to put a radio button with each repeating field (somehow) and have the button reference the currently selection on the repeating field.  
1601826609

Edited 1601826701
GiGs
Pro
Sheet Author
API Scripter
Oh dear, now you're getting into the headache-y stuff, hehe. It is possible to do this, but it can be tricky. It's hard for me to suggest a complete solution, because I need to know more about what you're trying to achieve. What are the 3 repeating fields? How do you know which row to use from each field? The simplest way to do something like this is to have a hidden attribute to hold the die for for each repeating section. This attribute is outside the repeating section.  Whenever the players change the active row in the repeating section, a sheet worker updates the hidden attribute that holds its die. Then in your button, you just reference the three hidden attributes - since they aren't in repeating sections, the syntax is very simple. Post some more details, including relevant html samples, and I can post actual code to help illustrate the approach, or come up with a different one if this approach isnt valid for your situation.
This will take a bit.  I am in the middle of some unrelated stuff. 
1601833637

Edited 1601834174
GiGs
Pro
Sheet Author
API Scripter
As it happens i have some old code I could repurpose. So, getting a radio button to work in a repeating section isn't possible, because each row is in a hidden <repitem> block. But you can simulate it by having a sheet worker check which row was just clicked, and unclick any other rows. The tricky part here is that when you uncheck another row, that triggers the sheet worker again, and that can lead to undesired behaviour. Fortunately sheet workers can check if they were triggered by a player or a sheetworker, so you check check what triggered the worker and only use player triggered events. So with that basic problem described, here is a sheet worker that will do what I described earlier. To make this work you need to edit the first line of code, and there are some constants in the next 4 lines you might want to edit - but can leave at default. Here are those lines, with explanations of how to edit them following: ['section1', 'section2', 'section3'].forEach(section => {     const externalname = 'selected';     const diename = 'die';     const checkname = 'check';     const nonechecked = '0'; So you need three repeating sections. If your repeating sections are called repeating_gun, repeating_hovercar, repeating_tribble, change the first line to ['gun', 'hovercar', 'tribble'].forEach(section => { You must have three hidden inputs outside the repeating section. They can be anywhere as long as they are not in any repeating sections. Their names should be in the form sectionname_externalname . Each should have the exact same externalname . I've used selected in the code, so with the above code you might use <input type="hidden" name="attr_gun_selected" value="0" > <input type="hidden" name="attr_hovercar_selected" value="0" > <input type="hidden" name="attr_tribble_selected" value="0" > If you want to use a suffix different from selected, just change that second line to somethingelse, like      const   externalname  =  'somethingelse' ; Now, inside your repeating sections, you need two attributes - a checkbox, to show whether this row is active, and an input or select to hold the die value. These should be named sectionname_check  and sectionname_die . So with the above three sections they might be <input type="checkbox" name="attr_gun_check" value="1" > <input type="text" name="attr_gun_die" value="1d6" > <input type="checkbox" name="attr_hovercar_check" value="1" > <input type="text" name="attr_hovercar_die" value="1d6" > <input type="checkbox" name="attr_tribble_check" value="1" > <input type="text" name="attr_tribble_die" value="1d6" > You must  use the section name followed by a _ for these. If you want a different suffix from check and die, you can change that in lines 3 and 4 of the code, here:     const diename = 'die';     const checkname = 'check'; Finally, you need to dice what die value to use if no item is selected in the repeating section. Ive seyt a value of '0' in the 5th line here:      const   nonechecked  =  '0' ; Just change the 0 to whatever you want to use. Now, after that preamble, here is the code, with comments: [ 'section1' ,  'section2' ,  'section3' ]. forEach ( section   =>  {      const   externalname  =  'selected' ;      const   diename  =  'die' ;      const   checkname  =  'check' ;      const   nonechecked  =  '0' ;           on ( `change:repeating_ ${ section } : ${ section } _ ${ checkname }  change:repeating_ ${ section } : ${ section } _ ${ diename }  remove:repeating_ ${ section }  sheet:opened` , ( event )  =>  {          // need to find the row that the player just clicked          const   rowid  =  event . sourceAttribute  ?  event . sourceAttribute . split ( '_' )[ 2 ] :  0 ;          // need to find out if the worker was triggered by a player or a worker (itself):          const   worker  =  event . sourceType  ===  'sheetworker'  ?  true  :  false ;          // if triggered by a worker, stop worker, to simulate radio button.          if  ( worker )  return ;          // a function to build section attribute names to save typing later          const   sectionName  = ( section ,  id ,  field )  =>   `repeating_ ${ section } _ ${ id } _ ${ section } _ ${ field } ` ;          // need to get an array of all row ids in the 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 ,  checkname ),                  sectionName ( section ,  id ,  diename )             ));              // using that array, we can now use getAttrs to grab their values from the sheet.              getAttrs ( fieldnames ,  values   =>  {                  // create a holding attribute, which will hold all the values of attributes we will change on the sheet                  const   output  = {};                  // reset the dice attribute to 0, in case none of the rows are checked                  output [ ` ${ section } _ ${ externalname } ` ] =  nonechecked ;                                   // loop through each row in the section (using the row ids)                  idarray . forEach ( id   =>  {                      // grab the check value, we'll need it later;                      const   check  =  parseInt ( values [ sectionName ( section ,  id ,  checkname )]) ||  0 ;                      // we need to check if the id matches the one just clicked by the player                      if ( rowid  ===  id  ||  rowid  ===  0 ) {                          // if the row IS checked, we need to grab the die value and overwrite the attribute outside the repeating section                          if ( check ) {                              const   die  =  values [ sectionName ( section ,  id ,  diename )];                              // save that die in the external attribute for the button                              output [ ` ${ section } _ ${ externalname } ` ] =  die ;                         }                      }  else  {                          // 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)                          if ( check ) {                              output [ sectionName ( section ,  id ,  checkname )] =  0 ;                         }                     }                      // we have now looped through every row of the section, so lets update the character sheet.                      setAttrs ( output );                 });             });         });     }); }); And here's the html I used to test it: < button   type = "roll"   name = "rollbutton_test"   value = "/roll @{section1_selected} + @{section2_selected} + @{section3_selected}" > Test! </ button > < input   type = "hidden"   name = "attr_section1_selected"   value = "0"   > < input   type = "hidden"   name = "attr_section2_selected"   value = "0"   > < input   type = "hidden"   name = "attr_section3_selected"   value = "0"   > < span   name = "attr_section1_selected"   value = "0"   ></ span > < span   name = "attr_section2_selected"   value = "0"   ></ span > < span    name = "attr_section3_selected"   value = "0"   ></ span > < h2 > Section 1 </ h2 > < fieldset   class = "repeating_section1" >      < input   type = "text"   name = "attr_section1_name"   value = "a die" >      < input   type = "checkbox"   name = "attr_section1_check"   value = "1" >      < input   type = "text"   name = "attr_section1_die"   value = "d6" > </ fieldset > < h2 > Section 2 </ h2 > < fieldset   class = "repeating_section2" >      < input   type = "text"   name = "attr_section2_name"   value = "a die" >      < input   type = "checkbox"   name = "attr_section2_check"   value = "1" >      < input   type = "text"   name = "attr_section2_die"   value = "d6" > </ fieldset > < h2 > Section 3 </ h2 > < fieldset   class = "repeating_section3" >      < input   type = "text"   name = "attr_section3_name"   value = "a die" >      < input   type = "checkbox"   name = "attr_section3_check"   value = "1" >      < input   type = "text"   name = "attr_section3_die"   value = "d6" > </ fieldset > You should be able to tweak this to meet your needs. Any questions, ask away.
Its early for me, so I will read all this after another cup of coffee.  But I said I would add more detail (which looks like it will be pointless, as GiGs stuff looks like it will do prefectly.) Okay, there is only two dice, and a skill modifier.  One die come from a drop down menu named after the attributes (strength, etc).  These are not in a repeating section.   The second die will be pulled from a repeating section (named "repeating_items").  I was thinking each will have a radio button or a checkbox to indicate which is being used in the roll.  There will be some additional information listed in that field that will be pulled as well (item_name, item_type, item_quality, and item_notes), but these will not factor into the math.  I have done this before so I can do that. The skill modifiers will be pulled from another repeating field.  This will be only a flat number to be added or subjected from the total rolled.   Alright, time to fetch that sweet, sweet caffeine. 
1601919561
GiGs
Pro
Sheet Author
API Scripter
Since you only have two repeating sections, and they are both handled differently, a slightly different arrangement than I posted earlier would be needed. Same basic principle, but slightly different details.
1602032315

Edited 1602039739
GiGs
Pro
Sheet Author
API Scripter
For your second die, there's a modified sheet worker below. You can copy this worker and make some changes and use it for the third modifier too. As with my previous post there's some configuration stuff at the start you can alter to fit your needs. I'll describe that here: This is the bit to modify: on ( `change:repeating_items:item_check change:repeating_items:item_name change:repeating_items:item_type change:repeating_items:item_quality change:repeating_items:item_notes remove:repeating_items sheet:opened` , ( event )  =>  {      // create default values and a relationship table of input fields to output:      const   section  =  'items' ;      const   checkbox  =  'item_check' ;      const   relationships  = {          item_name :  { output :   'output_name' ,  default :   '-' },          item_type :  { output :   'output_type' ,  default :   '-' },          item_quality :  { output :   'output_quality' ,  default :   '0' },          item_notes :  { output :   'output_notes' ,  default :   '-' },     }; On the first line, you need to enter the names for each attribute on the section you are monitoring. For you second die, that looks like 5 attributes: 4 whose values you want to grab (item_name, item_type, item_quality, and item_notes), and a fifth, a checkbox you can click to mark active.  On the subsequent lines: const section: enter the repeating section name here. const checkbox: enter the name of the checkbox attribute. I've used item_check. Change it to whatever your checkbox is named. Then theres a variable called relationships . You should have one line for each attribute whose value you want to grab (which in your case is item_name, item_type, item_quality, and item_notes). On that same line there is an output  property and a default property. The output property is the name of the attribute outside the repeating section where you want to save that value. I've put in some guesses because I don't know what yours are called - just change them to match yours. The default  property is the value you want those external attributes to be set when nothing is selected in the repeating section. Change them to what you need. So you can make multiple copies of this worker (maybe two, one for your second die, and one for your modifier), and just change the above lines to fit the workers. The relationships variable can have a different number of lines. You could reduce it to just one, if you are just grabbing a single value from a repeating section. Just make sure the first line (the on(changes) line) gets updated to the correct attribute names. Here is the code: on ( `change:repeating_items:item_check change:repeating_items:item_name change:repeating_items:item_type change:repeating_items:item_quality change:repeating_items:item_notes remove:repeating_items sheet:opened` , ( event )  =>  {      // create default values and a relationship table of input fields to output:      const   section  =  'items' ;      const   checkbox  =  'item_check' ;      const   relationships  = {          item_name :  { output :   'output_name' ,  default :   '-' },          item_type :  { output :   'output_type' ,  default :   '-' },          item_quality :  { output :   'output_quality' ,  default :   '0' },          item_notes :  { output :   'output_notes' ,  default :   '-' },     };           // need to find the row that the player just clicked      const   rowid  =  event . sourceAttribute  ?  event . sourceAttribute . split ( '_' )[ 2 ] :  0 ;      // need to find out if the worker was triggered by a player or a worker (itself):      const   worker  =  event . sourceType  ===  'sheetworker'  ?  true  :  false ;      // if triggered by a worker, stop worker, to simulate radio button.      if  ( worker )  return ;      // a function to build section attribute names to save typing later      const   sectionName  = ( section ,  id ,  field )  =>   `repeating_ ${ section } _ ${ id } _ ${ field } ` ;      // need to get an array of all row ids in the 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 ,  checkbox )));          idarray . forEach ( id   =>   Object . keys ( relationships ). 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   =>  {             // need to check if attribute changed is on the row that is checked. If not do nothing.             const   activerow  = ! rowid  ?  1  :  parseInt ( values [ sectionName ( section ,  rowid ,  checkbox )]) ||  0 ;             if (! activerow )  return ;              // 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 ( relationships ). forEach ( key   =>   output [ relationships [ key ]. output ] =  relationships [ key ]. default );                           // loop through each row in the section (using the row ids)              idarray . forEach ( id   =>  {                  // grab the check value, we'll need it later;                  const   check  =  parseInt ( values [ sectionName ( section ,  id ,  checkbox )]) ||  0 ;                  if ( check ) {                  // we need to check if the id matches the one just clicked by the player                      if ( 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 ( relationships ). forEach ( key   =>  {                              //console.log(`${key} = ${relationships[key]}`);                              output [ relationships [ key ]. output ] =  values [ sectionName ( section ,  id ,  key )];                         });                     }  else  {                          // 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 ,  checkbox )] =  0 ;                     }                 }                  // we have now looped through every row of the section, so lets update the character sheet.                  setAttrs ( output );             });         });     }); });
1602032434
GiGs
Pro
Sheet Author
API Scripter
The html I used to test the previous code. You dont have to use hidden inputs and visible spans. Visible inputs should work fine. < button   type = "roll"   name = "rollbutton_test"   value = "/roll @{output_quality}" > Test! </ button > < input   type = "hidden"   name = "attr_output_name"   value = ""   > < input   type = "hidden"   name = "attr_output_type"   value = ""   > < input   type = "hidden"   name = "attr_output_quality"   value = "0"   > < input   type = "hidden"   name = "attr_output_notes"   value = ""   > < span   name = "attr_output_name"   value = ""   ></ span > < span   name = "attr_output_type"   value = ""   ></ span > < span    name = "attr_output_quality"   value = "0"   ></ span > < span    name = "attr_output_notes"   value = ""   ></ span > < h2 > Second Die Test </ h2 > < fieldset   class = "repeating_items" >      < input   type = "checkbox"   name = "attr_item_check"   value = "1"   >      < input   type = "text"   name = "attr_item_name"   value = "test"   >      < input   type = "text"   name = "attr_item_type"   value = "a new"   >      < input   type = "text"   name = "attr_item_quality"   value = "d6"   >      < input   type = "text"   name = "attr_item_notes"   value = "a note"   > </ fieldset >
1602040727

Edited 1602884229
GiGs
Pro
Sheet Author
API Scripter
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 );             });         });     }); });
Oh, boy. First off, thank you so much.  I am currently trying to work through this, and really appreciate all of this work. Second, this is going to take me a while.  I can't explain it, but I am having a really hard time absorbing this information.  Its explained in a way I can see is clear and easy to understand, but I am just not getting it.  Its like my brain is saying "Hang on, wait.  Not enough storage space, please delete some apps."  So, please bear with me while I figure this out. Which there isn't a lot to figure out, since you did all the work.  And that does not make me feel any better about having trouble understanding it. Again, thank you.
1602271708
Kraynic
Pro
Sheet Author
Coal Powered Puppet said: Which there isn't a lot to figure out, since you did all the work.  And that does not make me feel any better about having trouble understanding it. You aren't the only one.  I barely have a grip on simple html/css.  Sheetworkers mostly make my brain glaze over (I'm fairly certain it doesn't stop at the eyes).  I see threads like this and think:  "that's cool, I could probably use that somehow".  But that is usually about as far as it gets.
1602272333
GiGs
Pro
Sheet Author
API Scripter
I understand the confusion. I can tell you exactly what you need with a bit more information. You made this post earlier, but it's missing key info: Coal Powered Puppet said: Its early for me, so I will read all this after another cup of coffee.  But I said I would add more detail (which looks like it will be pointless, as GiGs stuff looks like it will do prefectly.) Okay, there is only two dice, and a skill modifier.  One die come from a drop down menu named after the attributes (strength, etc).  These are not in a repeating section.   The second die will be pulled from a repeating section (named "repeating_items").  I was thinking each will have a radio button or a checkbox to indicate which is being used in the roll.  There will be some additional information listed in that field that will be pulled as well (item_name, item_type, item_quality, and item_notes), but these will not factor into the math.  I have done this before so I can do that. The skill modifiers will be pulled from another repeating field.  This will be only a flat number to be added or subjected from the total rolled.   Alright, time to fetch that sweet, sweet caffeine.  These 3 bits of of info (2 dice and a flat modifier) get pulled from different places, but you dont say where they get put .  What is the html for the final result? I assume it has An input for the first die. At least to display the value of an input elsewhere on the sheet. for the second die, 4 attributes, which will hold the information from the items repeating section, where these grabbed values go: item_name, item_type, item_quality, and item_notes. But you dont give the names of the attributes where they get saved. An input for your final flat modifier, taken from another repeating section. But you dont mention the name of that section, the name of the attribute to grab from within it, and the name of the attribute where it gets sent. So thats at least 6 attributes (maybe 5 - that first one might not need a distinct attribute of its own), but there might be more - more notes and labels sections for example. And probably a button which uses those values. So seeing that full html section would be great help in telling you what you need to do.
1602272679
GiGs
Pro
Sheet Author
API Scripter
Kraynic said: Coal Powered Puppet said: Which there isn't a lot to figure out, since you did all the work.  And that does not make me feel any better about having trouble understanding it. You aren't the only one.  I barely have a grip on simple html/css.  Sheetworkers mostly make my brain glaze over (I'm fairly certain it doesn't stop at the eyes).  I see threads like this and think:  "that's cool, I could probably use that somehow".  But that is usually about as far as it gets. Lol at your brain glazing over. Javascript is hard to understand, especially with no programming background. I'm always happy to help you get the code I post working. I can try to explain it so people can understand it, or I can just show what you need to do to plug it in and get it working. My last code post here is designed to be fairly easy to use that way - you dont need to understand it, you just need to figure out how to edit the first few lines to fit your goal. That can seem intimidating, but I am happy to help you figure out how to that.
Oh ^)*%$ this code is so sexy! Okay, so its working in the main area (than you so freaking much).  Now, the second repeating section is working...mostly.  Only one part isn't updating.  What am I doing wrong? html: <!-- --> <input type="hidden" name="attr_output2_name" value="" > <input type="hidden" name="attr_output2_rating" value="" > <input type="hidden" name="attr_output2_notes" value="" > <div class="hidden"> <span name="attr_output2_name" value="" ></span> <span name="attr_output2_rating" value="" ></span> <span name="attr_output2_notes" value="" ></span> </div> <!-- --> <fieldset class="repeating_skills"> <div class="compendium-drop-target"> <div class="row"> <div class="item 5"></div> <div class="item 20"> <div class="relative"> <input type="checkbox" class="repeat_selected" name="attr_skill_check" value="1" ><span></span> </div> </div> <div class="item 150"><button type="roll" class="ability" name="roll_skill" value="@{skill_name} @{skill_rating} @{skill_notes}"><span name="attr_skill_name"></span></button></div> <div class="item 5"></div> <div class="item 40"><span name="attr_skill_rating"></span></div> <div class="item 20"><input type="checkbox" name="attr_skill_toggle" class="gear" value="1"/><span></span></div> </div> <div> <input type="checkbox" name="attr_skill_toggle" class="hider hidden" value="1"/> <div class="hold"> <div class="row"> <div class="item 5"></div> <div class="item 180"><input type="text" class="text" name="attr_skill_name" placeholder="Name"/></div> <div class="item 50"><input type="text" class="text" name="attr_skill_rating" value="0"/></div> </div> <div class="halfrow"> <div class="item 5 subheader"></div> <div class="item 180 subheader">Name</div> <div class="item 50 subheader">Rating</div> </div> <div class="halfrow"></div> <div class="textarea_box"> <textarea class="textarea_2" name="attr_skill_notes" placeholder="Description"></textarea> </div> </div> </div> </div> </fieldset> And the sheetworker: on(`change:repeating_skills:skill_check change:repeating_skills:skill_name change:repeating_skills:skill_rating change:repeating_skills:skill_notes remove:repeating_skills sheet:opened`, (event) => { // create default values and a relationship table of input fields to output: const section = 'skills'; const checkbox = 'skill_check'; const relationships = { skill_name: {output: 'output2_name', default: '-'}, skill_rating: {output: 'output2_rating', default: '-'}, skill_notes: {output: 'output2_notes', default: '-'}, }; // need to find the row that the player just clicked const rowid = event.sourceAttribute ? event.sourceAttribute.split('_')[2] : 0; // need to find out if the worker was triggered by a player or a worker (itself): const worker = event.sourceType === 'sheetworker' ? true : false; // if triggered by a worker, stop worker, to simulate radio button. if (worker) return; // a function to build section attribute names to save typing later const sectionName = (section, id, field) => `repeating_${section}_${id}_${field}`; // need to get an array of all row ids in the 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, checkbox))); idarray.forEach(id => Object.keys(relationships).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 => { // need to check if attribute changed is on the row that is checked. If not do nothing. const activerow = !rowid ? 1 : parseInt(values[sectionName(section, rowid, checkbox)]) || 0; if(!activerow) return; // 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(relationships).forEach(key => output[relationships[key].output] = relationships[key].default); // loop through each row in the section (using the row ids) idarray.forEach(id => { // grab the check value, we'll need it later; const check = parseInt(values[sectionName(section, id, checkbox)]) || 0; if(check) { // we need to check if the id matches the one just clicked by the player if(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(relationships).forEach(key => { //console.log(`${key} = ${relationships[key]}`); output[relationships[key].output] = values[sectionName(section, id, key)]; }); } else { // 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, checkbox)] = 0; } } // we have now looped through every row of the section, so lets update the character sheet. setAttrs(output); }); }); }); });
1602816592
GiGs
Pro
Sheet Author
API Scripter
Can you say which bit isnt updating?
[grumble grumble] none of it right now.  The code won't even fail in a respectable manner. That is to say, there seems to be an issue when altering the inputs that will become the outputs when section I am updating happens to be selected, but that only occurs when I am updating an existing sheet attached to a character journal that existed before I installed the code you gave me. In short, I have no idea why things are working, I have no idea why they broke...in the same half second moment in time.  All I can say is there is no current problems in the code, thus far. If I were going to as for something, I would ask for a way for an action button to reset the output attributes.  That is to say, if it is normal for a character to select an attribute (radio button I can put a "0" value to), skill (repeating area using you code), and item (repeating area using you code), and hit the roll button, what is the way to set up a button that returns the repeating sections back to zero? I think I can puzzle this out in the next couple of days, so only answer if you have time after helping everyone else.   Thanks for your time.
1602819493

Edited 1602822805
GiGs
Pro
Sheet Author
API Scripter
Having a reset to default function is a good idea, and seems a pretty logical feature to add. I'll see about that. What you say about the problem in your second paragraph makes me wonder if there was some conflict of sheet workers each trying to change the same attributes, or  something about the default values isnt being handled properly in my code. Let me know if the problem reoccurs and add any extra details you can if that happens.
1602820367

Edited 1602884166
GiGs
Pro
Sheet Author
API Scripter
I notice you are using one of the earlier versions of the sheet worker. The last one I posted can be used for both the items and skill sections - code below. Note that you should remove both existing sheet workers before pasting this: Notice that the radio sections variable at the start is the user-edited area (change the defaults to whatever they should be). You could have it work with any number of repeating sections, just adding an extra block for each. This is the same code as in my last code post, just with the radio sections variable updated.     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: '-'},             }         },         skills: {             checkbox: {field: 'skill_check'},             fields: {                 skill_name: {output: 'output2_name', default: '-'},                 skill_rating: {output: 'output2_rating', default: '-'},                 skill_notes: {output: 'output2_notes', default: '-'},             }         },              };     // 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);                 });             });         });     });
1602828139

Edited 1602828151
GiGs
Pro
Sheet Author
API Scripter
I was thinking about resetting to defaults and realised I didnt know which defaults you mean. Do you mean having a reset button on a row of the repeating section, that resets just that row to default? Do you mean having a reset button outside the section that sets all rows to default? Do you mean having a rest button (where) that resets the external attributes to default? (this doesnt seem that useful, but is what I originally thought you meant till i started thinking about code). Something else?
The idea is that the player picks a attribute (radio button not in a repeating field), a skill (a repeating field) and an item (another repeating field), and then roll the dice.  It could be that they don't have an item or skill appropriate for the task.  The button, I guess, is to return the output text to the defaults.   I will try out this code and see what it does.
1602877981
GiGs
Pro
Sheet Author
API Scripter
The way I've written the code, you should be able to return the output text to default by unchecking whichever row is selected. IIRC deleting the checked row should do that too. Does that work properly?
I have installed the new code, and it works great.  But no, it does not reset to defaults.  I am thinking about putting a button in that does that, which with the help you already gave me, I know how to do.
1602884303
GiGs
Pro
Sheet Author
API Scripter
There was an error in my code (two actually, but one was subtle and wouldnt be visible). I;ve updated my last code post with the correction. Now it will reset output stats to default when unchecking a row, or deleting the checked row.
New code doesn't work.  Its not updating anything anymore. You have helped out tremendously already.  I will code a simple button to clear the outputs; you have done way more than anyone should every hope for you.
1602894319
GiGs
Pro
Sheet Author
API Scripter
Thats weird, I just copied the code from this post:&nbsp; <a href="https://app.roll20.net/forum/permalink/9283739/" rel="nofollow">https://app.roll20.net/forum/permalink/9283739/</a> into a html file with the html from this post:&nbsp; <a href="https://app.roll20.net/forum/permalink/9281679/" rel="nofollow">https://app.roll20.net/forum/permalink/9281679/</a> and its working fine. If it's not working for you, there is a problem somewhere, and it's a good idea to figure out what it is because it might be affecting more than just this worker. If you PM me a link to your complete html, I'll check it out and see what's causing the issue.