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 .
×
D&D 2024 has arrived! Pre-order the new core rulebooks now and get an exclusive pre-order bonus for free!
Create a free account

How to make some checkboxes on a repeating row hide based on a max number on that same row?

I have a custom charactersheet with a repeating row for different type of Stress... I'd like to make the number of Stress boxes (the check boxes) change based on the number in the Max column so that it looks more like...       <fieldset class="repeating_stress">          <input type="text" name="attr_stress_name" size="28" value=""/>            <input type="number" name="attr_stress_max" size="2" style="width:40px;" value="0"/>            <input type=checkbox name="attr_stress_chk1"> <input type=checkbox name="attr_stress_chk2"> <input type=checkbox name="attr_stress_chk3"> <input type=checkbox name="attr_stress_chk4"> <input type=checkbox name="attr_stress_chk5"> <input type=checkbox name="attr_stress_chk6">        </fieldset>     Is there some easy way to do this? I'm thinking there should be something I can do in CSS, but can't work out what.  If the only solution is Javascript then how do I get it to trigger when the Sheet is viewed as well as when the number is changed and is there an easy way to refer to the different rows. TIA
1683039489

Edited 1683057321
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Yes you can do this: HTML <fieldset class="repeating_stress"> <input type="text" name="attr_stress_name" size="28" value=""/> <input type="number" name="attr_stress_max" size="2" style="width:40px;" value="0"/> <input type="hidden" class="length-control" name="attr_stress_max" value="0"> <input type=checkbox class="controlled-length-1" name="attr_stress_chk1"> <input type=checkbox class="controlled-length-2" name="attr_stress_chk2"> <input type=checkbox class="controlled-length-3" name="attr_stress_chk3"> <input type=checkbox class="controlled-length-4" name="attr_stress_chk4"> <input type=checkbox class="controlled-length-5" name="attr_stress_chk5"> <input type=checkbox class="controlled-length-6" name="attr_stress_chk6"> </fieldset> CSS .length-control[value="0"] ~ [class^="controlled-length"], .length-control[value="1"] ~ .controlled-length-1 ~ *, .length-control[value="2"] ~ .controlled-length-2 ~ *, .length-control[value="3"] ~ .controlled-length-3 ~ *, .length-control[value="4"] ~ .controlled-length-4 ~ *, .length-control[value="5"] ~ .controlled-length-5 ~ *{ display:none; } The way this works is that we made a type="hidden" duplicate version of the max attribute. Inputs with a type of hidden actually have their value property change as the value of the attribute changes. This means we can actually style based on the value of the attribute. Note that I've removed the  s that you had in there. You really don't want to do spacing with html entities. I'd recommend doing that with css styling instead (likely with a margin-left or margin-right). I've also added some classes to make the targeting for the display easier.
1683042076

Edited 1683042220
GiGs
Pro
Sheet Author
API Scripter
It is possible to do this with CSS and a sheet worker. You need all the checkboxes created in html first, and each checkbox needs a hidden input that is set to 0 or 1 based on the value of the max button. Each hidden input would have a class, and each heckbox would have a different class. Your HTML would look like this (notice the addition of classes) < input type = "number" name = "attr_stress_max" class = "max" style = " width:40px;" value = "0" />                   < input type = "hidden" name = "attr_stress_1" class = "stress-toggle" value = "1" />         < input type = checkbox class = "buttons" name = "attr_stress_chk1" >           < input type = "hidden" name = "attr_stress_2" class = "stress-toggle" value = "1" />         < input type = checkbox class = "buttons" name = "attr_stress_chk2" >           < input type = "hidden" name = "attr_stress_3" class = "stress-toggle" value = "1" />         < input type = checkbox class = "buttons" name = "attr_stress_chk3" >           < input type = "hidden" name = "attr_stress_4" class = "stress-toggle" value = "1" />         < input type = checkbox class = "buttons" name = "attr_stress_chk4" >           < input type = "hidden" name = "attr_stress_5" class = "stress-toggle" value = "1" />         < input type = checkbox class = "buttons" name = "attr_stress_chk5" >           < input type = "hidden" name = "attr_stress_6" class = "stress-toggle" value = "1" />         < input type = checkbox class = "buttons" name = "attr_stress_chk6" > Seeing your HTML like this makes me think you should wrap the whole repeating section contents in a div, use CSS Grid to manage the columns and spacing, and get rid of the  . Ignoring that for now though. Then in CSS, you'd need this: .stress-toggle [ value = "0" ] + .buttons {     display : none ; } Notice the use of + there. That means the class affects only the element directly following it. So the stress_5 box affects only the checkbox immediately after it. This means you only need one copy of the above CSS, and it works for all rows and all buttons. Finally, to make it work, you need a sheet worker, which respods to your stress_max value and updates all the hidden inputs. on { `change:repeating_stress:stress_max` , () => {             getAttrs ( 'repeating_stress_stress_max' , v => {                 const limit = + v [ repeating_stress_stress_max ] || 0 ;                 const output = {};                 [ 1 , 2 , 3 , 4 , 5 , 6 ]. forEach ( i => {                     output [ `repeating_stress_stress_chk ${ i } ` ] = ( i <= limit ) ? 1 : 0 ;                 });                 setAttrs ( output );             });         }); This will automatically update the row you changed stress_max on, changing the hidden input values, so that those equal to or below its value are set to . This also handles pcs who enter a vakue greater than 6, which is very possible. Edit: I see I've been ninja'd by Scott with a more elegant solution :) (Ninja Turtled maybe - I shouldn't keep these tabs open while i look at other things...)
1683042674
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Edit:  I see I've been ninja'd by Scott with a more elegant solution :) (Ninja Turtled maybe - I shouldn't keep these tabs open while i look at other things...) Bwahahaha! I do that all the time too GiGs; usually you're the one that ninja's me.
1683042889
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Also, Mick, one more piece of code critique. For this input: <input type="number" name="attr_stress_max" size="2" style="width:40px;" value="0"/> I'd get rid of the size property. You're defining the width with your style property, and the size property is just an old way to do that same thing. Personally, I'd get rid of all of the size properties and use CSS styling to define their widths. This is because the size property is a legacy property that has pretty much been supplanted by CSS and mixing the two has the chance to cause unintended behavior.
Thanks both - I’ll give that a whirl and take your advice on other styling/sizing too. One day I may even stop using TABLE too :)
1683052016

Edited 1683052079
GiGs
Pro
Sheet Author
API Scripter
Scott C. said: Edit:  I see I've been ninja'd by Scott with a more elegant solution :) (Ninja Turtled maybe - I shouldn't keep these tabs open while i look at other things...) Bwahahaha! I do that all the time too GiGs; usually you're the one that ninja's me. Hehe. I have two questions about your solution. In this <input type="number" name="attr_stress_max" size="2" style="width:40px;" value="0"/> <input type="hidden" class="length-control" name="attr_stress_max" value="0"> Why didn;t you h=just add the class to the first stress_max, like <input type="number" name="attr_stress_max" class="length-control" style="width:40px;" value="0"/> Does it have to be type="hidden" here? Second, how does your CSS work? .length-control[value=0] ~ [class^="controlled-length"], .length-control[value=1] ~ .controlled-length-1 ~ *, .length-control[value=2] ~ .controlled-length-2 ~ *, .length-control[value=3] ~ .controlled-length-3 ~ *, .length-control[value=4] ~ .controlled-length-4 ~ *, .length-control[value=5] ~ .controlled-length-5 ~ *{ display:none; } I was under the impression that values only apply to that one specific value. So if value=2, that one line would work, but the buttons for 1, 3-6 would become visible. Is this something to with the final ~ * (I'm not sure what that is doing here).
1683052134
GiGs
Pro
Sheet Author
API Scripter
Mick H. said: Thanks both - I’ll give that a whirl and take your advice on other styling/sizing too. One day I may even stop using TABLE too :) You should definitely stop using that, but you obviously know that :) Everything you do with TABLE, you can do with CSS Grid, and with less code.
I haven't been able to get this to work - tried both methods. With the Sheetworker mechanism... I had to tweak the code to get it to run. In the first line I changed curly bracket to a normal bracket, the backticks to quotes and made the middle underscore in repeating_stress_stress_max into a colon which made it follow the pattern of other Sheetworker examples I'd found...  on("change : repeating_stress : stress_max", () => { Also had to tweak the code to add some square brackets for the getAttrs... getAttrs( [ "repeating_stress_stress_max" ] , function(values) {                 const limit = values.repeating_stress_stress_max;                 console.log("my max="+limit); I'm now getting the values coming out in my console.log but no matter what I try I can't get my checkboxes to vanish. I even tried making all the hidden fields visible... the cvalues don't get toggled betwen 1 and 0 and changing their value manually from 1 to 0 still doesn't make them vanish and reappear. Any ideas?
1683057871

Edited 1683058045
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
I haven't been able to get this to work - tried both methods. Hey Mick, Sorry, I had a typo in my CSS. The value=0 (and the rest of the value='s) should have had the number wrapped in quotes. I've fixed that in the post so it should now work. The effect looks like this: If it still doesn't work for you, check if you are using legacy sanitization. If you are, you'll need to put sheet-  at the start of all those class calls in the CSS. e.g the first line of the CSS would now read: .sheet-length-control[value="0"] ~ [class^="sheet-controlled-length"], And then for GiGs' questions: In this <input type="number" name="attr_stress_max" size="2" style="width:40px;" value="0"/> <input type="hidden" class="length-control" name="attr_stress_max" value="0"> Why didn;t you h=just add the class to the first stress_max, like <input type="number" name="attr_stress_max" class="length-control" style="width:40px;" value="0"/> Does it have to be type="hidden" here? Yep, has to be type="hidden" . The hidden type has special behavior where the value of its value property actually updates to match what the value of the attribute is. This is why we have to use the duplicate; one for user editing, one for display control. Second, how does your CSS work? .length-control[value=0] ~ [class^="controlled-length"], .length-control[value=1] ~ .controlled-length-1 ~ *, .length-control[value=2] ~ .controlled-length-2 ~ *, .length-control[value=3] ~ .controlled-length-3 ~ *, .length-control[value=4] ~ .controlled-length-4 ~ *, .length-control[value=5] ~ .controlled-length-5 ~ *{ display:none; } I was under the impression that values only apply to that one specific value. So if value=2, that one line would work, but the buttons for 1, 3-6 would become visible. Is this something to with the final ~ * (I'm not sure what that is doing here). So, I'm taking advantage of the ordering of the checkboxes to do some simpler css rules. The rules above would break down to the following in pure english: If the value of our control input is 0, then set all inputs that have a class starting with controlled-length  to display:none . For each possible value of the control input, set only the inputs after the input matching that value to display:none. And finally, if the value of the control isn't contained in this definition, then don't do anything (since none of the css selectors will match it) This is really just an adaptation of one of the fill to left checkbox methods .
Thanks for this. I was sure it was my fault. I’ll finish setting it up tomorrow. I have needed to use “sheet-“ for some other things, so will check that too. It’s been a useful exercise for me as I’ve learned a lot about repeating secrions and sheet-workers while debuggging it - I have been a software developer for 35 yrs - lots of Javascript and HTML too but doing it all inside Roll20 framework takes some extra fiddling about. :) - grateful for your explanations
1683067929

Edited 1683067941
GiGs
Pro
Sheet Author
API Scripter
Mick, I notice a syntax error in my sheet worker. This line] const limit = +v[repeating_stress_stress_max] || 0; should be const limit = +v['repeating_stress_stress_max'] || 0; or const limit = +v.repeating_stress_stress_max || 0; You are correct to point out my quotes being random. But `, ', and " are interchangeable. It doesn't matter which you use as long as you are consistent about the begginning and end. There is one line where I used backticks, and you have to use backticks. This one: output[`repeating_stress_stress_chk${i}`] = (i <= limit) ? 1 : 0; Scott, thanks for that explanation. I understand the ~ * at the end of each row now, which was confusing me. I knew that about hidden attributes, but in my experience it has rarely mattered. I have wondered if Roll20 has updated it's code so that it's unncessary for a lot of situations where it used to be necessary. But I'm happy to accept if it is still necessary.