Please check out my fiddle below. A checkbox with nested checkboxes. The change function works fine: if any $('#checkbox' x)
is checked, the corresponding $('.entry' x)
shows, and if unchecked, hidden.
The initial state of my checkboxes is ignored until at least one of the checkboxes are clicked. In the example, initially all $('.entry' x)
show, although #checkbox1, -2 and -3 are initially checked. But: if I then uncheck #checkbox2, only .entry1 and .entry3 show, all other elements hide. From there on, everything works as expected.
I've tried the following:
$('#checkbox1').click();
so just clicking without "actually" clicking (leads to checkbox1 being unchecked but nothing else happens until I click on any of the checkboxes)setting a checkbox to
.prop('checked', true)
(pretty much the same result like in 1)I've also tried it with an if/else statement like
`
if ($('#checkbox' x).prop('checked') == 'true') {
$('.entry' x).show();
}
else{
$('.entry' x).hide();
}`
Still nothing. How do I gain control over the initial states of the checkboxes in this example? Please help me, I just can't figure it out. Just to make clear what i want to achieve: I'd like to be able to set the props to checked and have the checked/unchecked " x" elements be hidden and shown accordingly, and create .on('click', ...) events to change the props later on and have them always behave accordingly.
$(function () {
// CHECKBOXES GROU AND NESTED CHECKBOXES HIDE/SHOW SYNCHRONIZING
$.fn.nestedCheckboxes = function (stopPropogation) {
this.addClass('nestedCheckboxes');
this.on('click', ':has( > input[type=checkbox])', nestedCheckboxHandler);
function nestedCheckboxHandler(evt) {
if ($(evt.target).is("input[type=checkbox]")) {
var parentContainer = $(this);
var checkbox = parentContainer
.find(' > input[type=checkbox]:eq(0)');
var parentCheckbox = parentContainer
.parent()
.closest(':has( > input[type=checkbox])')
.children('input[type=checkbox]');
if (evt.target == checkbox[0]) {
$('input[type=checkbox]', parentContainer)
.prop("checked", checkbox.prop("checked"));
$(function () {
$(new Array(5).fill(1).map((_, i) => i 1)).each(function (idx, x) { // Array for the number of div elements
$('.entry' x)[($('#checkbox' x).prop("checked") ? "show" : "hide")](); // synchronize
$('#checkbox' x).on('change', function () { // toggle on change
$('.entry' x).toggle();
});
});
});
}
var parentCheckboxValue = !parentCheckbox
.parent()
.find("input[type=checkbox]")
.not(parentCheckbox[0])
.is("input[type=checkbox]:not(:checked)");
parentCheckbox.prop("checked", parentCheckboxValue);
} else if (stopPropogation) {
evt.stopPropagation();
}
};
};
$('.treeX-container form').nestedCheckboxes();
});
* {
list-style-type:none;
}
.l0{
color: #000;
font-weight: bold;
}
.entry1,
.l1{
color: #ff3333;
}
.entry2,
.l2{
color: #003DFF;
}
.entry3,
.l3{
color: #FF8A0E
}
.entry4,
.l4{
color: #45F300;
}
.entry5,
.l5{
color: #E700EF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
<ul>
<form>
<li>
<input type="checkbox"/>
<span >ALL</span>
<ul>
<li>
<input type="checkbox" id="checkbox1" value="1" checked />
<label >Entry1</label>
</li>
<li>
<input type="checkbox" id="checkbox2" value="1" checked />
<label >Entry2</label>
</li>
<li>
<input type="checkbox" id="checkbox3" value="1" checked />
<label >Entry3</label>
</li>
<li>
<input type="checkbox" id="checkbox4" value="1" />
<label >Entry4</label>
</li>
<li>
<input type="checkbox" id="checkbox5" value="1" />
<label >Entry5</label>
</li>
</ul>
</li>
</form>
</ul>
</div>
<div >
<div >ENTRY1</div>
<div >ENTRY2</div>
<div >ENTRY3</div>
<div >ENTRY4</div>
<div >ENTRY5</div>
</div>
CodePudding user response:
Here is a slightly simplified approach. showHideEntries()
is a utility function that runs a loop over all checkboxes and sets the visibility of the associated entries below. It is called initially in the jQuery onl oad routine and later on whenever a checkbox is clicked.
$cb
is a jQuery object that references all the "normal" (single) checkboxes.
$(function() {
const $cb = $(".treeX-container")
.on("click", "input", function() {
if (!this.id)
$cb.prop("checked", this.checked);
showHideEntries();
}).find("ul ul input");
function showHideEntries() {
$cb.each(function() {
$("." this.id.replace("checkbox", "entry")).toggle(this.checked)
})
}
showHideEntries();
});
* {
list-style-type: none;
}
.l0 {
color: #000;
font-weight: bold;
}
.entry1,
.l1 {
color: #ff3333;
}
.entry2,
.l2 {
color: #003DFF;
}
.entry3,
.l3 {
color: #FF8A0E
}
.entry4,
.l4 {
color: #45F300;
}
.entry5,
.l5 {
color: #E700EF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
<ul>
<form>
<li>
<label ><input type="checkbox"/>
ALL</label>
<ul>
<li>
<input type="checkbox" id="checkbox1" value="1" checked />
<label for="checkbox1">Entry1</label>
</li>
<li>
<input type="checkbox" id="checkbox2" value="1" checked />
<label for="checkbox2">Entry2</label>
</li>
<li>
<input type="checkbox" id="checkbox3" value="1" checked />
<label for="checkbox3">Entry3</label>
</li>
<li>
<input type="checkbox" id="checkbox4" value="1" />
<label for="checkbox4">Entry4</label>
</li>
<li>
<input type="checkbox" id="checkbox5" value="1" />
<label for="checkbox5">Entry5</label>
</li>
</ul>
</li>
</form>
</ul>
</div>
<div >
<div >ENTRY1</div>
<div >ENTRY2</div>
<div >ENTRY3</div>
<div >ENTRY4</div>
<div >ENTRY5</div>
</div>
Here is another answer to the extended question, as posted in your comment below (building on V2 of your JSfiddle):
$(function() {
$(".treeX-container")
.on("click", "input", function() {
var $cb;
if (!this.id){ // a group checkbox was clicked
$cb=$("ul:first input",this.closest("li")); // get all subordinate checkboxes
$cb.prop("checked",this.checked); // and set them accordingly
} else $cb=$(this); // an individual checkbox option was clicked
showHideEntries($cb);// update visibility of associated entry elements
});
function showHideEntries($cb) {
$cb.each(function() {
if (this.id) $("." this.id.replace("checkbox", "entry")).toggle(this.checked)
});
}
showHideEntries($("input"));
});
* {
list-style-type: none;
font-size: 14px;
}
.l0 {
color: #000;
font-weight: bold;
}
.container {}
.item {
background-color: #999999;
width: 20px;
height: 20px;
padding: 10px;
line-height: 20px;
display: inline-block;
border-radius: 20px;
text-align: center;
vertical-align: middle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
<ul>
<form>
<li>
<label ><input type="checkbox" />
ALL</label>
<ul>
<li>
<label><input type="checkbox" id="checkbox1" value="1" checked />
Entry1</label>
</li>
<li>
<label><input type="checkbox" id="checkbox2" value="1" checked />
Entry2</label>
</li>
<li>
<label><input type="checkbox" id="checkbox3" value="1" checked />
Entry3</label>
</li>
<li>
<label ><input type="checkbox" />
CheckboxGroup</label>
<ul>
<li>
<label><input type="checkbox" id="checkbox4" value="1" checked />
Entry4</label>
</li>
<li>
<label><input type="checkbox" id="checkbox5" value="1" checked />
Entry5</label>
</li>
<li>
<label><input type="checkbox" id="checkbox6" value="1" checked />
Entry6</label>
</li>
<li>
<label><input type="checkbox" id="checkbox7" value="1" />
Entry7</label>
</li>
<li>
<label ><input type="checkbox" />
CheckboxGroup</label>
<ul>
<li>
<label><input type="checkbox" id="checkbox8" value="1" checked />
Entry8</label>
</li>
<li>
<label><input type="checkbox" id="checkbox9" value="1" checked />
Entry9</label>
</li>
<li>
<label><input type="checkbox" id="checkbox10" value="1" checked />
Entry10</label>
</li>
<li>
<label><input type="checkbox" id="checkbox11" value="1" />
Entry11</label>
</li>
<li>
<label><input type="checkbox" id="checkbox12" value="1" />
Entry12</label>
</li>
</ul>
</li>
<li>
<label><input type="checkbox" id="checkbox13" value="1" />
Entry13</label>
</li>
</ul>
</li>
<li>
<label><input type="checkbox" id="checkbox14" value="1" />
Entry14</label>
</li>
<li>
<label><input type="checkbox" id="checkbox15" value="1" />
Entry15</label>
</li>
</ul>
</li>
</form>
</ul>
</div>
<div >
<div >1</div>
<div >2</div>
<div >3</div>
<div >4</div>
<div >5</div>
<div >6</div>
<div >7</div>
<div >8</div>
<div >9</div>
<div >10</div>
<div >11</div>
<div >12</div>
<div >13</div>
<div >14</div>
<div >15</div>
</div>
I had to rearrange the logic a little bit to deal with the different sets of checkboxes it needs to collect. Center part is now the expression $cb=$("ul:first input",this.closest("li"));
that collects all the checkboxes of the "next ul" in case one of the "collection" checkboxes was clicked. this.closest("li")
(a Vanilla-JS expression!!!!) moves up to the closest li
element and from there on the jQuery selector "ul:first input"
will find all input elements below the first ul
element it encounters.
I also changed your label
s such that they always surround the associated checkbox. This way you can click on a label text to activate the checkbox inside the label.