We use Cookies to help personalize and improve Roll20. For more information on our use of non-essential Cookies, visit our Privacy Policy here.
Accept
Advertisement Create a free account

[Sheet Authors] hide/show or sort repeating rows based on an attribute value found in the repeating row possible?

1589095206
Vince
Pro
Sheet Author
Is it possible to hide/show repeating rows based on the value of an attribute used in the row?  example;  hide/show spells on a sheet based on their @{level} I'm guessing that rowID's might be problematic...  Maybe this is possible using sheetworkers?  Even sorting repeating rows would be beneficial, right?  Re-sort skills alphabetically, spells by level, etc.  Thoughts?
1589097414
GiGs
Pro
Sheet Author
API Scripter
I'm not clear what you're asking. It would be handy to know what sort of value you want the visibility to set by. Without it we are just guessing. You can hide bits of a repeating row based on a value within the row. You'd just use that technique and expand it, no sheet worker needed. Put all the contents of the fieldset inside a div, and then a hidden attribute before the div, something like this <fieldset class="repeating_something">     <input type="hidden" name="attr_hideme" value="0" class="toggle-row" />     <div class="section-to-hide">         <!-- all the contents of the fieldset go here including this probably:-->         <input type="number" name="attr_hideme" value="0" />     </div> </fieldset> Then use the value of the hiddent attribute to toggle the visibility. You can have a copy of that hidden attribute inside the div, so you can manually set it or show its value. Sorting is a very different issue than Hiding/Showing. Its possible to do that with a sheet worker, but its really complex. You essentially have to copy the contents of the rows into new attributes in the order you want them, and delete the old ones.
1589098254

Edited 1589098554
Vince
Pro
Sheet Author
Hi GiGs, so, I have a sheet that has a repeating_spells section.  All spells(levels 0-9) are located within repeating_spells.  I would like to only show the level of spells, 0-9, selected from a checkbox/button found outside the repeating_spells. ie select level 3, and only see level 3 spells. I assume that the value of @{repeating_spells_$X_level} could be used to determine if a repeating row is shown.  I played around with adding a hidden @{level} located just before the outermost element within the fieldset (not unlike your example), but that didn't seem to work upon my first efforts.  If I can get this to work, it will save me having to add an additional 9 repeating sections. ;-)
1589100200

Edited 1589100457
GiGs
Pro
Sheet Author
API Scripter
CSS isnt my best skill, but I remember seeing a post about this specific topic: having tabs within a repeating section for showing levels of spells. I havent tried it, but you might get what you need here:&nbsp;<a href="https://app.roll20.net/forum/permalink/3094981/" rel="nofollow">https://app.roll20.net/forum/permalink/3094981/</a> And a follow up post here&nbsp; <a href="https://app.roll20.net/forum/permalink/4314678/" rel="nofollow">https://app.roll20.net/forum/permalink/4314678/</a>
1589100477

Edited 1589100541
Vince
Pro
Sheet Author
Thanks GiGs.&nbsp; I'm sure it just requires a little CSS acrobatics. :-) edit: and of course I commented in those very threads.&nbsp; lol
1589100808
GiGs
Pro
Sheet Author
API Scripter
I was talking to rabulias recently about whether it was better to have a different repeating section for each spell level or one repeating section for all spells. I couldnt understand why anyone would do a repeating section for each level, but this thread has made me understand why - so you can show/hide groups of spells easily. I do wonder if the method I suggested (using a hidden attribute for the fieldset row) can be made to work. Possibly having the tabs be outside the fieldset and be action buttons that trigger a sheet worker. If so it would be simpler than Chris's method. I may experiment with that tomorrow-&nbsp; but its bedtime for me now.&nbsp;
1589100872
GiGs
Pro
Sheet Author
API Scripter
Vince said: edit: and of course I commented in those very threads.&nbsp; lol Hehe, i noticed that - but it was 4 years ago!
1589100964

Edited 1589101109
Vince
Pro
Sheet Author
I think I can do something like .repcontainer &gt; div.repitem input.sheet-spells_0_tab:not(:checked) + .sheet-sect, .repcontainer &gt; div.repitem input.sheet-spells_1_tab:not(:checked) + .sheet-sect { &nbsp; &nbsp; display:none; } time for bed...
1589104405

Edited 1589105263
GiGs
Pro
Sheet Author
API Scripter
I fiddled with this while having supper, and this solution works. HTML: &lt;div&nbsp;class="spell_tabs"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;type="radio"&nbsp;name="attr_spell_tabs"&nbsp;value="-1"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;type="radio"&nbsp;name="attr_spell_tabs"&nbsp;value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;type="radio"&nbsp;name="attr_spell_tabs"&nbsp;value="1"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;type="radio"&nbsp;name="attr_spell_tabs"&nbsp;value="2"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;type="radio"&nbsp;name="attr_spell_tabs"&nbsp;value="3"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;type="radio"&nbsp;name="attr_spell_tabs"&nbsp;value="4"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;type="radio"&nbsp;name="attr_spell_tabs"&nbsp;value="5"&gt; &lt;/div&gt; &lt;fieldset&nbsp;class="repeating_spells"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;type="hidden"&nbsp;class="toggle-show"&nbsp;name="attr_spell_show"&nbsp;value="1"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;div&nbsp;class="spell-display"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;label&gt;Level&nbsp;&lt;span&nbsp;name="attr_spell_level"&gt;&lt;/span&gt;&lt;/label&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;select&nbsp;name="attr_spell_level"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;option&nbsp;selected&gt;-1&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;option&gt;0&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;option&gt;1&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;option&gt;2&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;option&gt;3&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;option&gt;4&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;option&gt;5&lt;/option&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/select&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt; &lt;/fieldset&gt; CSS div.sheet-spell-display&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;display:none; } input.sheet-toggle-show[value="1"]&nbsp;~&nbsp;div.sheet-spell-display&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;display:&nbsp;inline-block; } Sheet worker on('change:spell_tabs',&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getSectionIDs('repeating_spells',&nbsp;idarray&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fieldnames&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray.forEach(id&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fieldnames.push(`repeating_spells_${id}_spell_level`); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs(['spell_tabs',&nbsp;...fieldnames],&nbsp;v&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;output&nbsp;=&nbsp;{}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;level&nbsp;=&nbsp;+v.spell_tabs||0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray.forEach(id&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;thislevel&nbsp;=&nbsp;+v[`repeating_spells_${id}_spell_level`]&nbsp;||&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output[`repeating_spells_${id}_spell_show`]&nbsp;=&nbsp;(level&nbsp;===&nbsp;-1&nbsp;||&nbsp;level&nbsp;===&nbsp;thislevel)&nbsp;?&nbsp;1&nbsp;:&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(output); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); So, I have a set of radio buttons at the top for choosing spell level: they set the value of a&nbsp; spell_tabs attribute. &nbsp;They dont have to be radio buttons. You could use action buttons or any other approach, so long as a single attribute (named spell_tabs in this example) is set to the level you want to display. Then in the fieldset, you have a hidden attribute named spell_show , and the bulk of the fieldset row inside a div. Inside that div is an attribute for the spell_level. Remember that every attribute on a repeating section is unique: this attribute's full name is repeating_spells_ID_spell_show . So the sheet worker checks whenever spell_tabs changes, and and loops through the repeating section to check the spell level of that row. The matching follows these rules: &nbsp; &nbsp; set the spell_show attribute to 1 IF the spell_tabs attribute is -1 (a setting to show all spells), or the spell_level = spell_tabs (the spell level is the same as the tab selected) And the CSS rule hides the section if the spell_show is 0, and shows it if 1. Note the spell_show attribute needs a default value of 1, or any new spells you try to create will be hidden! See if this works for you. Note: new spells wont be hidden, until you change the spell tabs again. That could easily be changed&nbsp; - either the spell level or some other value in the section could trigger the sheet worker to calculate spell_show, so that it updates automatically. just add that the the sheet worker line like so on('change:spell_tabs&nbsp;change:repeating_spells:spell_level',&nbsp;()&nbsp;=&gt;&nbsp;{ But you want to be careful here-&nbsp; players could accidentally hide a spell before they finish entering the details. So having a button to say "finished entering spell details" or similar, they can click finish and then it will be hidden if it doesnt match the active spell level.
1589112406
Chris D.
Pro
Sheet Author
API Scripter
The Earthdawn by FASA sheet, on the grimoire tab, has a good example of how it works.&nbsp;
1589114774

Edited 1589114804
GiGs
Pro
Sheet Author
API Scripter
Just for clarity - the method I posted above isn't quite the same as the one from your old thread or the FASA sheet, it doesnt to use the hidden radio tabs or the repcontainer references in CSS, for example.
1589153662
Vince
Pro
Sheet Author
Just wanted to say this works great GiGs!&nbsp; I just need to decide how I'm going to incorporate my spell tab system, but upon my first implementation, outstanding.
1589154044
GiGs
Pro
Sheet Author
API Scripter
Thanks, that's great!&nbsp;
1589160376

Edited 1589160773
Here is a minimal-as-I-can-get-it set of HTML and CSS for the method I use. It sounds like GiGs' solution works for you, but this is here for future users too (maybe even me one day ;-). HTML: &lt;input type="radio" class="spellclass01-spells-tab0" name="attr_tab_spellclass01_spells" title="Level 0" value="0"&gt; &lt;span&gt;Level 0&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab1" name="attr_tab_spellclass01_spells" title="Level 1" value="1"&gt; &lt;span&gt;Level 1&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab2" name="attr_tab_spellclass01_spells" title="Level 2" value="2"&gt; &lt;span&gt;Level 2&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab3" name="attr_tab_spellclass01_spells" title="Level 3" value="3"&gt; &lt;span&gt;Level 3&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab4" name="attr_tab_spellclass01_spells" title="Level 4" value="4"&gt; &lt;span&gt;Level 4&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab5" name="attr_tab_spellclass01_spells" title="Level 5" value="5"&gt; &lt;span&gt;Level 5&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab6" name="attr_tab_spellclass01_spells" title="Level 6" value="6"&gt; &lt;span&gt;Level 6&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab7" name="attr_tab_spellclass01_spells" title="Level 7" value="7"&gt; &lt;span&gt;Level 7&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab8" name="attr_tab_spellclass01_spells" title="Level 8" value="8"&gt; &lt;span&gt;Level 8&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab9" name="attr_tab_spellclass01_spells" title="Level 9" value="9"&gt; &lt;span&gt;Level 9&lt;/span&gt; &lt;input type="radio" class="spellclass01-spells-tab99" name="attr_tab_spellclass01_spells" title="All" value="99" checked&gt; &lt;span&gt;All Spells&lt;/span&gt; &lt;div class="spell-list"&gt; &lt;div style="margin-top:5px;"&gt; &lt;span&gt;&lt;b&gt;ENTER SPELL NAME AND SELECT LEVEL&lt;/b&gt;&lt;/span&gt; &lt;/div&gt; &lt;fieldset class="repeating_spellclass01spell"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab0" name="attr_spellclass01_spell_level" value="0"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab1" name="attr_spellclass01_spell_level" value="1"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab2" name="attr_spellclass01_spell_level" value="2"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab3" name="attr_spellclass01_spell_level" value="3"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab4" name="attr_spellclass01_spell_level" value="4"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab5" name="attr_spellclass01_spell_level" value="5"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab6" name="attr_spellclass01_spell_level" value="6"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab7" name="attr_spellclass01_spell_level" value="7"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab8" name="attr_spellclass01_spell_level" value="8"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab9" name="attr_spellclass01_spell_level" value="9"&gt; &lt;input type="radio" class="hidden spellclass01-spells-tab99" name="attr_spellclass01_spell_level" value="99" checked&gt; &lt;div class="filtered-box"&gt; &lt;span&gt; &lt;input type="text" class="inputbox" style="width: 300px;" name="attr_spellclass01_spell_name" title="repeating_spellclass01spell_$x_spellclass01_spell_name" placeholder="Spell name"&gt; &lt;/span&gt; &lt;span&gt; &lt;select name="attr_spellclass01_spell_level" style="width:44px;" title="repeating_spellclass01spell_$x_spellclass01_spell_level"&gt; &lt;option value="99"&gt;-&lt;/option&gt; &lt;option value="0"&gt;0&lt;/option&gt; &lt;option value="1"&gt;1&lt;/option&gt; &lt;option value="2"&gt;2&lt;/option&gt; &lt;option value="3"&gt;3&lt;/option&gt; &lt;option value="4"&gt;4&lt;/option&gt; &lt;option value="5"&gt;5&lt;/option&gt; &lt;option value="6"&gt;6&lt;/option&gt; &lt;option value="7"&gt;7&lt;/option&gt; &lt;option value="8"&gt;8&lt;/option&gt; &lt;option value="9"&gt;9&lt;/option&gt; &lt;/select&gt; &lt;/span&gt; &lt;/div&gt; &lt;/fieldset&gt; &lt;/div&gt; CSS: .sheet-hidden { display: none; } .sheet-filtered-box { display: none; } /* ===== HIDES EXTRA REPEATING SECTION BUTTONS WHEN USING FILTER BOX ====== */ .repcontainer .repitem { overflow: hidden; } input.sheet-spellclass01-spells-tab99:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab99:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem .sheet-filtered-box, .sheet-spellclass01-spells-tab0:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab0:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab1:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab1:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab2:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab2:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab3:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab3:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab4:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab4:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab5:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab5:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab6:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab6:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab7:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab7:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab8:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab8:checked~.sheet-filtered-box, .sheet-spellclass01-spells-tab9:checked~.sheet-spell-list&gt;fieldset.repeating_spellclass01spell+.repcontainer&gt;.repitem input.sheet-spellclass01-spells-tab9:checked~.sheet-filtered-box { display: block; }
1589163777
GiGs
Pro
Sheet Author
API Scripter
thanks for posting that - its nice to see a version of the older method stripped down just to what we need to know how to use it.
1589168072
Vince
Pro
Sheet Author
I really appreciate another option Rabulias.&nbsp; I really like that you don't need to use a sheetworker for your method. I hope other authors will grab these and run with them.&nbsp; I can't believe I've been creating extra repeating sections for spells by level when I can get away with a single fieldset and hide/show as needed.&nbsp; Hinge moment for me.
1589176420
GiGs
Pro
Sheet Author
API Scripter
Rabulias, I notice your fieldshet is called: &lt;fieldset class="repeating_spellclass01spell"&gt; Are you using a different repeating section per class?&nbsp; This made me think of using one section for all classes and levels, as well as spell-like powers. So you could have one section to track everything that has mostly the same attributes that a spell does. You could build more complex tabs that let you pick more than one criteria to show at once, too. This would just take modifying the sheet worker, and the initial tabs that set the filter.&nbsp; I think it would be trickier to do with Chris's method, but much could be done with a bit of extra set up: you'd need a much bigger set of hidden radio buttons and some way of constructing a single attribute that combined class and spell level to use as the filter.&nbsp;
1589177027

Edited 1589177184
GiGs
Pro
Sheet Author
API Scripter
Here's what the sheet worker might look like on('change:spell_tabs&nbsp;change:class_tabs',&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;getSectionIDs('repeating_spells',&nbsp;idarray&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fieldnames&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray.forEach(id&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fieldnames.push(`repeating_spells_${id}_spell_level`); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fieldnames.push(`repeating_spells_${id}_spell_class`); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs(['spell_tabs',&nbsp;'spell_class',&nbsp;...fieldnames],&nbsp;v&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;output&nbsp;=&nbsp;{}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;level&nbsp;=&nbsp;+v.spell_tabs||0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;spellclass&nbsp;=&nbsp;+class_tabs&nbsp;||0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray.forEach(id&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;thislevel&nbsp;=&nbsp;+v[`repeating_spells_${id}_spell_level`]&nbsp;||&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;thisclass&nbsp;=&nbsp;+v[`repeating_spells_${id}_spell_class`]&nbsp;||&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output[`repeating_spells_${id}_spell_show`]&nbsp;=&nbsp;(level&nbsp;===&nbsp;-1&nbsp;||&nbsp;level&nbsp;===&nbsp;thislevel)&nbsp;&amp;&amp;&nbsp;(spellclass&nbsp;===&nbsp;-1&nbsp;||&nbsp;spellclass&nbsp;===&nbsp;thisclass)&nbsp;?&nbsp;1&nbsp;:&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(output); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;}); }); In this case, the tabs for selected class have numerical values (the text they display would be the class name, but each has a numerical value behind the scenes). But that's not necessary, text could be used just as easily. Your initial tabs now have 4 options: Level tab is set to show all levels level tab is set to a specific level Class tab is set to show all classes class tab is set to show specific class And it will show all spells that match whichever class and level are selected. You could even expand to different filters: show all fire spells, show all spells that require material components, all spells with "heal" in the name, etc. It's a mini-compendium on a sheet! One issue is sorting: spells would be shown in order of creation. Which could be very disorganised when you show all classes and levels. This can be sorted manually, but it would probably be worth having a a sheet worker to sort the section. But as stated earlier, that technically requires to to copy, delete, and paste the copied rows in the desired order. It's certainly do-able, but it's irritating there's no easier way to do it, and you dont want to be deleting user data unless you are certain the code is rock-solid.
1589177406

Edited 1589177447
Vince
Pro
Sheet Author
GiGs said: One issue is sorting: spells would be shown in order of creation. Which could be very disorganised when you show all classes and levels. This can be sorted manually, but it would probably be worth having a a sheet worker to sort the section. But as stated earlier, that technically requires to to copy, delete, and paste the copied rows in the desired order. It's certainly do-able, but it's irritating there's no easier way to do it. This is exactly what I was coming to ask about. lol I know people will inquire once they start using the new spell tabs. ;-) Too bad roll20 doesn't have a built-in method to sort when you use the reptiem to modify(rearrange) repeating rows.&nbsp;
1589177755

Edited 1589177921
GiGs
Pro
Sheet Author
API Scripter
What critieria would you use to sort by? Spell name, Spell class, spell level? some combination of them? Honestly I think sorting is do-able (though as noted - there's always a risk when you are deleting user date - especially as laggy as roll20 is right now), and I'll work up code for it, but I dont think it's really needed. Spells are going to to be created one by one, and it would be most sensible for players to manually sort them into the position they want them as they are created. That lets them sort them in the order they want them.&nbsp;
1589178578

Edited 1589178743
Vince
Pro
Sheet Author
GiGs said: What critieria would you use to sort by? Spell name, Spell class, spell level? some combination of them? Yes.&nbsp; lol Level 0-9 would be nice. People love choices.&nbsp; They have gotten used to using dedicated apps that let them easily sort data and they expect it on roll20 sheets as well.&nbsp; Even if it isn't realistic.&nbsp; Most people don't understand the limitations that sheet authors must work within. But honestly, I don't think it's that big of a deal for the AD&amp;D1e sheet.&nbsp; Now if this was Pathfinder...&nbsp;
1589180071

Edited 1589181132
GiGs
Pro
Sheet Author
API Scripter
Here's an example of what a sort function might look like that just sorted by name, to illustrate the complexity. (untested) This assumes you have a button to click to start the sort routine. You could set different filters to sort by, but I went with the simplest in this example. Using reduce instead of forEach could make this shorter but would be harder to understand the steps involved. The fields array at the start should include the name of every attribute within the row of the section. const&nbsp;fields&nbsp;=&nbsp;['spell_name',&nbsp;'spell_class',&nbsp;'spell_level']; on('clicked:sort_spells',&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;getSectionIDs('repeating_spells',&nbsp;idarray&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fieldnames&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;get&nbsp;the&nbsp;name&nbsp;of&nbsp;EVERY&nbsp;attribute&nbsp;on&nbsp;every&nbsp;row. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray.forEach(id&nbsp;=&gt;&nbsp;fields.forEach(field&nbsp;=&gt;&nbsp;fieldnames.push(`repeating_spells_${id}_${field}`))); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs(fieldnames,&nbsp;v&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;allrows&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;need&nbsp;to&nbsp;go&nbsp;throw&nbsp;every&nbsp;row&nbsp;and&nbsp;get&nbsp;the&nbsp;values,&nbsp;and&nbsp;store&nbsp;them&nbsp;with&nbsp;out&nbsp;the&nbsp;id &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray.forEach(id&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;get&nbsp;all the&nbsp;value&nbsp;of&nbsp;every&nbsp;attribute&nbsp;ibn&nbsp;a&nbsp;row,&nbsp;and&nbsp;story&nbsp;it&nbsp;in&nbsp;object&nbsp;with&nbsp;the&nbsp;field&nbsp;name &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;thisrow&nbsp;=&nbsp;{}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fields.forEach(field&nbsp;=&gt;&nbsp;thisrow[field]&nbsp;=&nbsp;v[`repeating_spells_${id}_${field}`]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allrows.push[thisrow]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;at&nbsp;this&nbsp;point&nbsp;we&nbsp;have&nbsp;all&nbsp;the&nbsp;attributes&nbsp;from&nbsp;the&nbsp;repeating&nbsp;section&nbsp;in&nbsp;an&nbsp;array&nbsp;of&nbsp;objects&nbsp;that&nbsp;looks&nbsp;something&nbsp;like &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{spell_name:&nbsp;'a&nbsp;spell',&nbsp;spell_class:&nbsp;'cleric',&nbsp;spell_level:&nbsp;3}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{spell_name:&nbsp;'another&nbsp;spell',&nbsp;spell_class:&nbsp;'cleric',&nbsp;spell_level:&nbsp;3}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{spell_name:&nbsp;'yet&nbsp;another&nbsp;spell',&nbsp;spell_class:&nbsp;'wizard',&nbsp;spell_level:&nbsp;1}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;now&nbsp;we&nbsp;need&nbsp;to&nbsp;sort&nbsp;the&nbsp;array.&nbsp;The&nbsp;Underscore&nbsp;function&nbsp;_.sortBy&nbsp;is&nbsp;easiest&nbsp;here &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allrows&nbsp;=&nbsp;_.sortBy(allrows,'spell_name'); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;now&nbsp;we&nbsp;create&nbsp;a&nbsp;new&nbsp;output&nbsp;function &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;output&nbsp;=&nbsp;{}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allrows.forEach(row&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//need&nbsp;to&nbsp;create&nbsp;a&nbsp;new&nbsp;id for each row, and create new complete repeating section attribute names for each field &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;rowid&nbsp;=&nbsp;generateRowID(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fields.forEach(field&nbsp;=&gt;&nbsp;output[`repeating_spells_${rowid}_${field}`]&nbsp;=&nbsp;row[field]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;now&nbsp;we&nbsp;have&nbsp;a&nbsp;sorted&nbsp;copy&nbsp;of&nbsp;the&nbsp;rows&nbsp;we&nbsp;can&nbsp;add&nbsp;to&nbsp;the&nbsp;repeating section.&nbsp;But&nbsp;we&nbsp;also&nbsp;need&nbsp;to&nbsp;delete&nbsp;the&nbsp;old&nbsp;set. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray.forEach(id&nbsp;=&gt;&nbsp;removeRepeatingRow(`repeating_spells_${id}`)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;finally&nbsp;update&nbsp;the&nbsp;sheet.&nbsp;If&nbsp;a connection&nbsp;error&nbsp;happens&nbsp;between&nbsp;the&nbsp;previous&nbsp;row&nbsp;and&nbsp;next&nbsp;row,&nbsp;the&nbsp;entire&nbsp;repeating&nbsp;section&nbsp;is&nbsp;lost&nbsp;forever. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(output, {silent:true}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;}); }); The data loss possibility does suggest that it would be a good idea to implement an undo function. That adds even more complexity.&nbsp; That said, data loss due to connection error on roll20 almost never happens (I've never experienced it), so I may be overstating the dangers. Its probably robust enough.&nbsp; And I'm assuming that roll20 will create new rows in the order they are in the output object. That should be tested, lol. If it doesn't, then there;s no way to sort via sheet worker at all.
1589180670
Vince
Pro
Sheet Author
You just whipped that up huh?&nbsp; ;-) Data loss would definitely be a concern.&nbsp; We had an issue on migrating spells on the pathfinder sheet.&nbsp; Some users lost some of their customized macro-text.&nbsp; It was always a concern moving forward.&nbsp; Chris B. added backups and buttons with warnings "HERE BE DRAGONS" that the user had to push after migrating data from an old schema to a newer one.&nbsp;&nbsp; I appreciate the time/effort you have put in on this already.&nbsp; No need to continue.&nbsp; I think most people that use the sheet will be thrilled to just be able to filter their spells by level.
1589181071
GiGs
Pro
Sheet Author
API Scripter
Vince said: You just whipped that up huh?&nbsp; ;-) Data loss would definitely be a concern.&nbsp; We had an issue on migrating spells on the pathfinder sheet.&nbsp; Some users lost some of their customized macro-text.&nbsp; It was always a concern moving forward.&nbsp; Chris B. added backups and buttons with warnings "HERE BE DRAGONS" that the user had to push after migrating data from an old schema to a newer one.&nbsp;&nbsp; I appreciate the time/effort you have put in on this already.&nbsp; No need to continue.&nbsp; I think most people that use the sheet will be thrilled to just be able to filter their spells by level. I wanted to see what the code would look like, so I didnt mind working on it as a proof of concept.&nbsp; One way to mitigate the data loss danger would be recommend players make backups of their character sheets, but you cant do that from a sheet worker. You could print a warning after pressing the sort button, then show the real sort button, lol. But for something people expect to be easy, having a "be careful this may destroy your data" warning probably isn't the best feature. I found an old post wherein Jakob mentioned it was almost possible to sort non-destructively, by manipulating the reporder attributes-&nbsp; but only almost &nbsp;possible. So still not possible. That's a shame. So its probably best to stick with manual sorting.
1589182057
Vince
Pro
Sheet Author
There's probably a suggestion for it somewhere... Character Sheet - move repeating fields up/down &nbsp;(5 years ago)
1589182700
GiGs
Pro
Sheet Author
API Scripter
I wonder if that suggestion dates from before we got the ability to manually sort repeating sections. That wasnt something we always had.