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

Character Sheet making, Can't show and hide checkboxes based on values

Hello I've been racking my brain trying to make extra checkboxes appear based on a global value, I have gotten this far based on searching, prayers and chatpgt, but some issues not even that thing can help me with, I've tried to use checkboxes to hide/show etc stuff, but I'm just too damn inexperienced to figure this out. Now the game have a ton of checkboxes I want to show/hide based on Rank in skills, and based on your numerical value in 3 core stats.... I'm using tabs and that work, I'm just wondering if I've forgotten something simple, like a hidden input, but checkboxes didn't make it work eaither so..... Just give me some suggestions, I've used the code on the wiki for tab buttons and such, but this whole checkboxes shown when a specific value is at a spot is just messing with me, sadly :( atm my checkboxes uses <input type="checkbox" name="attr_cl3" class="health-clarity-1"> and I can hide or show them with a pure css block, I just can't get the toggle part to work
1704994103

Edited 1705077137
GiGs
Pro
Sheet Author
API Scripter
Don't use chatGPT for anything intended for Roll20. The version of html used here is idiosyncratic enough, with a small enough userbase, that chatGPT cannot produce code that will work here. Making lots of checkboxes visible or hidden is one of the most tedious things you can do on Roll20. Are you trying to make all checkboxes visible or hidden at the same time, or are they meant to be shown or hidden individually? If the former, you can do this with a single hidden input. If the latter, you need another hidden input for every single rule. Every box you want to hide or show needs its own hidden input. The technique is pretty simple, using a sheet worker to update all the hidden inputs in one fell swoop. But we'd need to know more details to come up with a solution. What are the rules that cause checkboxes to show or hide, and what attributes are they dependent on?
Okay, they only change with 1 change, clicking a checkbox doesn't change them. the attributes I'm using are foc/vit/wil these should show healthboxes the more you have in them the skills show hitboxes only if the skill have a B A or S rank, else they should be hidden, I'm really understanding that chatgpt isn't optimal, but I'm mainly using it to automate some things for me, and making the sheet look pretty if you need more info, just let me know, I'm fine with posting code of what I want to do, and such aswell, and in worst case I just won't add this functionality
1705009845
GiGs
Pro
Sheet Author
API Scripter
I definitely need more info. Like you have healthboxes - but how many? how many types? "the skills show hitboxes only if the skill have a B A or S rank, else they should be hidden" - for each skill, you'll need a sheet worker that checks if it is B, A, or S, and sets a hidden input to 0 or 1. (You can be clever about this and limit the number of sheet workers to just 1). The class of that hidden input then sets if the checkboxes for that skill are visible (bets to put them all in a div, one div per skill, so you can hide it easily.
Okay I'll give you the snippet code for one of each This is how every health thing looks, <div class="wounds-row lblue"> <div class="wounds-title">Light</div> <div class="wounds-options"> <input type="checkbox" name="attr_cl1"> <input type="checkbox" name="attr_cl2"> <input type="checkbox" name="attr_cl3" class="health-clarity-1"> <input type="checkbox" name="attr_cl4" class="health-clarity-4"> </div> </div> the skills look similar to each other: <div class="combat-skill"> <div class="combat-skill-name">Athletics</div> <div class="combat-skill-rank"><input type="text" name="attr_athletics_rank"></div> <div class="combat-checkboxes"> <input type="checkbox" title="-1 Intitative Point" name="attr_athletics_1"> <input type="checkbox" title="Reroll" name="attr_athletics_2"> <input type="checkbox" title="Replace Result with +1" name="attr_athletics_3"> <input type="checkbox" title="Ignore Negative Dice" name="attr_athletics_4"> <input type="checkbox" title="Replace Result with +2" name="attr_athletics_5"> <input type="checkbox" title="Gain 3 Temp Strain" name="attr_athletics_6"> </div> </div> I haven't started working on tryint to hide those boxes yet, since I figured I just need to figure out how to hide one box and then I can reuse that code as much as possible
there are 3 diffrent Health types, and each type have a maximum of 10 boxes shown in 3 diffrent rows, but always have 5 boxes shown with 5 more optional if the stat for them is 1 or higher
1705069807
GiGs
Pro
Sheet Author
API Scripter
This doesn't relate to your question, but in each checkbox I'd put value="1", like <input type="checkbox" name="attr_cl1" value="1"> This makes manipulating them with CSS and sheet workers easer. When checked they will have a value (=1) and when unchecked they have value = 0. You don't have to mess with checked:on, and can manipulate them as if they were numbers (and the pair of numbers 0 and 1 have special advantages). For your wounds, what is the attribute they are based on, and is the HTML for that attribute close? I;m gussing foc/vit/wil, but how do those scores change which boxes are shown? For your skill check boxes, they are shown if athletics_rank is BAS, and hidden otherwise? By the way, you have this <div class="combat-skill-rank"><input type="text" name="attr_athletics_rank"></div> That should probably be <input type="text" name="attr_athletics_rank" class="combat-skill-rank"> Any styling you have applied to that div can often be applied directly to the input.
Okay, I plan on doing a full on pass over the whole document later to make it look better (codewise) Anyway, from the rules that I'm using each point in foc/vit/wil, grands one more box in a specific spot, the input for these are way way in another spot (since I plan on having 1 page of the sheet that you update values on for levelup and such, so you don't accidently change them while changing another value... Also I don't have to change check the value of said checkboxes to see if they are active or not, (well except one per row) but that's good to know for later! And yes for the skills, they should be hidden unless the rank is BAS, each one showing more boxes, each rank adding 2 of the boxes! And thank you already for your help GiGs, I know you've been helping people a long time, and I apriate it!
1705077082
GiGs
Pro
Sheet Author
API Scripter
Tjacu said: And thank you already for your help GiGs, I know you've been helping people a long time, and I apriate it! Thank you! I'll post solutions for your issues as i undersand them once I've eaten. In the meantime. another answer that doesn't relate to your specific problem: The skills being a text input raises my eyebrows. You might find it better to replace with with a select like, <select name="attr_athletics_rank"> <option selected></option> <option>B</option> <option>A</option> <option>S</option> </select> Change the order of options however you need them, and add any extra legal values. When you know what the entry text should be, it's best to restrict the entry so players can't enter anything else - it avoids typoes you'll need to deal with and standardises the sheets data.
Ahha, yes, the plan is to use a sheetworker to update them to their raw value get changed, since people apply points to them, atm we just needed something that works for us while I work on it to add more and more functionality, else I would have done this from the start (probably)
1705083283
GiGs
Pro
Sheet Author
API Scripter
If people have the correct data in them at present, changing it from a text input to a select will work without needing anything to transform the data. It'll still be saved as a B A S, whatever whether a select or input. If their data is incorrect, it'll default to a non-entry, which will show up as the first item in the select dropdown. The attribute will be whatever the value they entered, but it can't be displayed in the select. It'll still be visible on the list on the Attributes & Abilities tab. If you don't have many people using the sheet and know them all, it would be better to make the change and manually update the few who need it (most should work without needing any changes).
1705084294

Edited 1705085735
GiGs
Pro
Sheet Author
API Scripter
Your skill rank needs the smallest change, so I'll start here: <div class="combat-skill"> <div class="combat-skill-name">Athletics</div> <div class="combat-skill-rank"><input type="text" name="attr_athletics_rank"></div> <input type="hidden" name="attr_athletics_display" value="0" class="stat-show"> <div class="combat-checkboxes"> <input type="checkbox" title="-1 Intitative Point" name="attr_athletics_1"> <input type="checkbox" title="Reroll" name="attr_athletics_2"> <input type="checkbox" title="Replace Result with +1" name="attr_athletics_3"> <input type="checkbox" title="Ignore Negative Dice" name="attr_athletics_4"> <input type="checkbox" title="Replace Result with +2" name="attr_athletics_5"> <input type="checkbox" title="Gain 3 Temp Strain" name="attr_athletics_6"> </div> </div> Notice I have added a single hidden input here.For each skill, create a hidden input, whether the name is [something]_display, repeating the [something] with exactly the same as you have before [something]_rank. They must be identical. You need two more bits - a bit of CSS and a sheet worker. Here's the sheet worker const skills = [ "athletics" , /* other skills */ ];     skills . forEach ( skill => {         on ( `change: ${ skill } _rank` , () => {             getAttrs ([ ` ${ skill } _rank` ], values => {                 const rank = values [ ` ${ skill } _rank` ];                 const output = {};                 if ( rank == 'B' || rank == "A" || rank == 'S' ) {                     output [ ` ${ skill } _display` ] = 1 ;                 } else {                     output [ ` ${ skill } _display` ] = 0 ;                 }                 setAttrs ( output );             });         });     }); The only line of this you need to chance is the const skills = part at the start. Just add each skill name there, as recognised by roll20 (the bit before _rank) Finally the CSS is really simple input.stat-show:not ([ value = "1" ]) + div.combat-checkboxes {     display : none ; } You don't need a separate rule for each skill - this one rule will handle them all. The + means the very next item. So if the input.stat-show has a value that is not 1, the next item is hidden if and only if it is a div with class combat-checkboxes. So this rule can handle any number of skills, since each input's value affects only the div that immediately follows.
1705085610
GiGs
Pro
Sheet Author
API Scripter
Note these sheet workers only trigger when the attribute is changed, so if the sheets are already in use you might not see an immediate change. In that case, you should change this line: on(`change:${skill}_rank`, () => { to on(`change:${skill}_rank sheet:opened`, () => { But I would change it back, once you know every sheet has been opened (by anyone) at least once.
Perfect this works amazingly well!!! Any way for the HP checkboxes?
Sorry just realized how selfish that sounded, currently in a game and been working away with all the other parts all day long :D
I tested it out and I realised I must have given you the wrong info at one point, it should show 2 checkboxes on B rank 4 checkboxes on A rank and 6 checkboxes on S rank, it's still better than nothing atm, just figured I should say I guess I could just duplicate this and add another class for each level.... that is probably the easiest way to do it
1705089854

Edited 1705090134
GiGs
Pro
Sheet Author
API Scripter
You will need to add another class  for each level, and a separate hidden input for each level too (but a single sheet worker can set all 3). CSS cant do greater then, it has to be exact equals or not equals, which makes things like this more laborious than it should be, sadly. What is in your current css block combat-checkboxes?
1705090645

Edited 1705098222
GiGs
Pro
Sheet Author
API Scripter
Here's another approach (if your combat-checkboxes block has borders or similar, it would need a slightly different design - easy to update): <div class="combat-skill"> <div class="combat-skill-name">Athletics</div> <div class="combat-skill-rank"><input type="text" name="attr_athletics_rank"></div> <input type="hidden" name="attr_athletics_display_1" value="0" class="stat-show"> <div class="combat-checkboxes"> <input type="checkbox" title="-1 Intitative Point" name="attr_athletics_1"> <input type="checkbox" title="Reroll" name="attr_athletics_2"> </div> <input type="hidden" name="attr_athletics_display_2" value="0" class="stat-show"> <div class="combat-checkboxes"> <input type="checkbox" title="Replace Result with +1" name="attr_athletics_3"> <input type="checkbox" title="Ignore Negative Dice" name="attr_athletics_4"> </div> <input type="hidden" name="attr_athletics_display_3" value="0" class="stat-show"> <div class="combat-checkboxes"> <input type="checkbox" title="Replace Result with +2" name="attr_athletics_5"> <input type="checkbox" title="Gain 3 Temp Strain" name="attr_athletics_6"> </div> </div> Notice you need an hidden input  for each div you want to hide, and it should be directly before it. Here is the rewritten sheet worker. const skills = [ "athletics" , /* other skills */ ];         skills . forEach ( skill => {             on ( `change: ${ skill } _rank` , () => {                 getAttrs ([ ` ${ skill } _rank` ], values => {                     const rank = values [ ` ${ skill } _rank` ];                     const output = {};                     if ( rank == 'B' ) {                         output [ ` ${ skill } _display_1` ] = 1 ;                         output [ ` ${ skill } _display_2` ] = 0 ;                         output [ ` ${ skill } _display_3` ] = 0 ;                     } else if ( rank == "A" ) {                         output [ ` ${ skill } _display_1` ] = 1 ;                         output [ ` ${ skill } _display_2` ] = 1 ;                         output [ ` ${ skill } _display_3` ] = 0 ;                     } else if ( rank == 'S' ) {                         output [ ` ${ skill } _display_1` ] = 1 ;                         output [ ` ${ skill } _display_2` ] = 1 ;                         output [ ` ${ skill } _display_3` ] = 1 ;                     } else {                         output [ ` ${ skill } _display_1` ] = 0 ;                         output [ ` ${ skill } _display_2` ] = 0 ;                         output [ ` ${ skill } _display_3` ] = 0 ;                     }                     setAttrs ( output );                 });             });         }); This uses the same skill list in the first line. The CSS is unchanged input.stat-show:not ([ value = "1" ]) + div.combat-checkboxes {     display : none ; } How does this work for you?
1705091577

Edited 1705146331
Edit: This have been edited it the post and is no longer needed to do. Just in case people look this up later I hade to add } before else if and else if Elsewise yes it works, I'm just gonna need to change some visual code for it! Ty!!
Ohh I just saw that you wanted to see my combat-checkboxes, here it is: .combat-checkboxes { display: flex; grid-column: 3; flex-direction: row; justify-content: space-between; align-items: center; }
1705098146
GiGs
Pro
Sheet Author
API Scripter
The main reason I wanted to see them was to see if splitting into three divs would change the visual appearance. That wont change anything, so great!
1705098195
GiGs
Pro
Sheet Author
API Scripter
Tjacu said: Just in case people look this up later I hade to add } before else if and else if Elsewise yes it works, I'm just gonna need to change some visual code for it! Ty!! Oh yes, good point. I had a small syntax error there, going back to fix it again in case anyone uses it later.
1705098368
GiGs
Pro
Sheet Author
API Scripter
Tjacu said: there are 3 diffrent Health types, and each type have a maximum of 10 boxes shown in 3 diffrent rows, but always have 5 boxes shown with 5 more optional if the stat for them is 1 or higher I missed this earlier. Are you saying that there are 5 boxes that show all the time, and boxes 6-10 show if the stat is 1 or higher? You posted this for the wounds earlier and I don't see how the match up: <div class="wounds-row lblue"> <div class="wounds-title">Light</div> <div class="wounds-options"> <input type="checkbox" name="attr_cl1"> <input type="checkbox" name="attr_cl2"> <input type="checkbox" name="attr_cl3" class="health-clarity-1"> <input type="checkbox" name="attr_cl4" class="health-clarity-4"> </div> </div>
I'll post a full box! <!-- First set of rows --> <div class="wounds-row lblue"> <div class="wounds-title">Light</div> <div class="wounds-options"> <input type="checkbox" name="attr_cl1"> <input type="checkbox" name="attr_cl2"> <input type="checkbox" name="attr_cl3"> <input type="checkbox" name="attr_cl4"> </div> </div> <!-- Second set of rows --> <div class="wounds-row lblue"> <div class="wounds-title">Severe</div> <div class="wounds-options"> <input type="checkbox" name="attr_cs1"> <input type="checkbox" name="attr_cs2"> <input type="checkbox" name="attr_cs3"> <input type="checkbox" name="attr_cs4"> </div> </div> <!-- Third set of rows --> <div class="wounds-row lblue"> <div class="wounds-title">Critical</div> <div class="wounds-options"> <input type="checkbox" name="attr_cc1"> <input type="checkbox" name="attr_cc2"> </div> </div> </div>
I only posted one line of the code, there are 3 boxes like this, but they all follow the same logic with how they are, using "attr_cl1", "attr_hl1", "attr_sl1" as checkbox values
1705129273
GiGs
Pro
Sheet Author
API Scripter
I still need to know which boxes should be hidden, based on stat score.
Okay, for this, I think the best checkboxes to hide (for later) is to hide box 1,2 for lightly and wounded and 1 for critical (cause there are things tied to the last checkbox filled in, so better to add one between them instead. And then it gives this: Statvalue = checkbox to show 1 = cl1 2 = cs1 3 = cc1 4 = cl2 5 = cs2 Is this the kind of info you wanted, or do you need more?
1705147530

Edited 1705147630
GiGs
Pro
Sheet Author
API Scripter
There might be a failure to communicate here. I want you to explain how many wound boxes are visible in every circumstance. I cant show you the needed code without knowing that. Forget about trying to describe roll20 stats, just describe how you would to a player at your table. How many wound boxes of each level does a character have?
Okay, that makes more sense. from the book, it gives a chart: Stat : Boxes 0 : 2 lighty wounded, 2 seriously wounded, 1 critical wounded 1 : 3 lighty wounded, 2 seriously wounded, 1 critical wounded 2 : 3 lighty wounded, 3 seriously wounded, 1 critical wounded 3 : 3 lighty wounded, 3 seriously wounded, 2 critical wounded 4 : 4 lighty wounded, 3 seriously wounded, 2 critical wounded 5 : 4 lighty wounded, 4 seriously wounded, 2 critical wounded Is this what you were after?
1705164651

Edited 1705164703
GiGs
Pro
Sheet Author
API Scripter
That's exactly what I was after. I'll have a proper look this evening. And so, you want to show the number of boxes a character actually has available, at their stat level?
Yes, always show the boxes that are available at their skill level!
1705176249

Edited 1705177083
GiGs
Pro
Sheet Author
API Scripter
Okay, for all the checkboxes you want to hide, you'll need to give them both an individual class, and a hidden input. If they follow the same rule for how they are hidden, you can get away with one input, but you need at least one input for each different rule (each wound level from 1-5 in your case). This is because of a limitation in the way CSS works, and I wish it wasn't so (You cannot test for values greater than or less than, you can only test for equals or not equals). So, the HTML for the foc wounds could be   < div class= "wounds-row lblue" >     < div class= "wounds-title" > Light </ div >     < div class= "wounds-options" >       < input type= "checkbox" name= "attr_cl1" >       < input type= "checkbox" name= "attr_cl2" >       < input type= "hidden" name= "attr_foc_1" class= "wound" >       < input type= "checkbox" name= "attr_cl3" class= "hide" >       < input type= "hidden" name= "attr_foc_4" class= "wound" >       < input type= "checkbox" name= "attr_cl4" class= "hide" >     </ div >   </ div >   <!-- Second set of rows -->   < div class= "wounds-row lblue" >     < div class= "wounds-title" > Severe </ div >     < div class= "wounds-options" >       < input type= "checkbox" name= "attr_cs1" >       < input type= "checkbox" name= "attr_cs2" >       < input type= "hidden" name= "attr_foc_2" class= "wound" >       < input type= "checkbox" name= "attr_cs3" class= "hide" >       < input type= "hidden" name= "attr_foc_5" class= "wound" >       < input type= "checkbox" name= "attr_cs4" class= "hide" >     </ div >   </ div >   <!-- Third set of rows -->   < div class= "wounds-row lblue" >     < div class= "wounds-title" > Critical </ div >     < div class= "wounds-options" >       < input type= "checkbox" name= "attr_cc1" >       < input type= "hidden" name= "attr_foc_3" class= "wound" >       < input type= "checkbox" name= "attr_cc2" class= "hide" >     </ div >   </ div > </ div > Notice there's a hidden attribute just before the checkbox that will be hidden, which also has a class. This method allows you to use the same CSS rule as before: input.stat-show:not ([ value = "1" ]) + div.combat-checkboxes , input.wound:not ([ value = "1" ]) + input .hide {     display : none ; } Finally, the tricky part is the Sheet worker.         const wounds = [ "foc" , /* other wound stats  */ ];         wounds . forEach ( wound => {             on ( `change: ${ wound } ` , () => {                 getAttrs ([ wound ], values => {                     const wound = Math . min ( 5 , Math . max ( 0 , + values [ wound ] || 0 ));                     // wound must range from 0 to 5.                     const output = {};                     [ 1 , 2 , 3 , 4 , 5 ]. forEach ( box =>  {                         if ( box <= wound ) {                             output [ ` ${ wound } _ ${ box } ` ] = 1 ;                         } else {                             output [ ` ${ wound } _ ${ box } ` ] = 0 ;                         }                     });                     setAttrs ( output );                 });             });         }); Anyone who's followed my posts knows I'd swap that if statement for a ternary operator: const wounds = [ "foc" , /* other wound stats  */ ];         wounds . forEach ( wound => {             on ( `change: ${ wound } ` , () => {                 getAttrs ([ wound ], values => {                     const wound = Math . min ( 5 , Math . max ( 0 , + values [ wound ] || 0 ));                     // wound must range from 0 to 5.                     const output = {};                     [ 1 , 2 , 3 , 4 , 5 ]. forEach ( box =>  {                         output [ ` ${ wound } _ ${ box } ` ] = ( box <= wound ) ? 1 : 0 ;                     });                     setAttrs ( output );                 });             });         }); These two sheet workers are identical in function, the second just has a slightly less understandable but more compact if statement. Again, once you've verified this works in the way you want, you might want to use the sheet:opened trick to get everyone initially updated, and then remove it once every sheet has been opened at least once.
Okay, I'm back from a small break, a lot of code and all that and my brain kinda needed a reset, I'm trying to get it to work but I'm getting in the console: ReferenceError: can't access lexical declaration 'wound' before initialization For my other calcs I use let foc = parseInt(values.foc)||0;
1705416724

Edited 1705417050
GiGs
Pro
Sheet Author
API Scripter
When you get this error ReferenceError: can't access lexical declaration 'wound' before initialization It usually means that the code is attempting to use a variable (in this case, 'wound') before it has been created. And I see the problem (not sure why I didn't catch this before). This line const wound = Math . min ( 5 , Math . max ( 0 , + values [ wound ] || 0 )); I'm trying to use the same variable name for two different things. That's creating confusion. So lets rewrite the code to fix that. const wounds = [ "foc" , /* other wound stats  */ ];         wounds . forEach ( wound => {             on ( `change: ${ wound } ` , () => {                 getAttrs ([ wound ], values => {                     const num = Math . min ( 5 , Math . max ( 0 , + values [ wound ] || 0 ));                     // num must range from 0 to 5.                     const output = {};                     [ 1 , 2 , 3 , 4 , 5 ]. forEach ( box =>  {                         if ( box <= num ) {                             output [ ` ${ wound } _ ${ box } ` ] = 1 ;                         } else {                             output [ ` ${ wound } _ ${ box } ` ] = 0 ;                         }                     });                     setAttrs ( output );                 });             });         }); I think this should do the trick.
it still doesn't show is this because they aren't showing or hiding a following div? It's making the foc_1 to 5 but nothing is hidden or shown based on it.... Could one of my classes be messing stuff up?
1705430856

Edited 1705431915
GiGs
Pro
Sheet Author
API Scripter
This one was a subtle error. I should have tested it first. Roll20 reserves some class names for special behaviour and doesnt tell you what those are, so you have to stumble over them. Anything with a class name of "hide" is always invisible. So change the class name of hide to something else, like this: HTML < div class= "wounds-row lblue" >     < div class= "wounds-title" > Light </ div >     < div class= "wounds-options" >       < input type= "checkbox" name= "attr_cl1" >       < input type= "checkbox" name= "attr_cl2" >       < input type= "hidden" name= "attr_foc_1" class= "wound" >       < input type= "checkbox" name= "attr_cl3" class= "check" >       < input type= "hidden" name= "attr_foc_4" class= "wound" >       < input type= "checkbox" name= "attr_cl4" class= "check" >     </ div >   </ div >   <!-- Second set of rows -->   < div class= "wounds-row lblue" >     < div class= "wounds-title" > Severe </ div >     < div class= "wounds-options" >       < input type= "checkbox" name= "attr_cs1" >       < input type= "checkbox" name= "attr_cs2" >       < input type= "hidden" name= "attr_foc_2" class= "wound" >       < input type= "checkbox" name= "attr_cs3" class= "check" >       < input type= "hidden" name= "attr_foc_5" class= "wound" >       < input type= "checkbox" name= "attr_cs4" class= "check" >     </ div >   </ div >   <!-- Third set of rows -->   < div class= "wounds-row lblue" >     < div class= "wounds-title" > Critical </ div >     < div class= "wounds-options" >       < input type= "checkbox" name= "attr_cc1" >       < input type= "hidden" name= "attr_foc_3" class= "wound" >       < input type= "checkbox" name= "attr_cc2" class= "check" >     </ div >   </ div > </ div > CSS: input.wound:not ([ value = "1" ]) + input.check {     display : none ; } And it should work. You might need to refresh the sandbox.
Check, also by using your code, I understood how to take the number value from _points and turn them into _rank! I felt proud! Also it works now!!! TY!!! You are the greatest GiGs