Reputation: 115
I have 8 groups of checkboxes. Each with a "master" and between 8 and 12 sub-checkboxes and try to create a "un/select all" behaviour to each group.
I found this SO https://stackoverflow.com/a/25697142/9098325 but it only shows one group of checkboxes.
I made a fiddle with my not working solution here: https://jsfiddle.net/ex4rnq83/
$('.outer').on('click', function() {
if (this.checked) {
$('.inner').each(function() {
this.checked = true;
});
} else {
$('.inner').each(function() {
this.checked = false;
});
}
});
$('.inner').on('click', function() {
if ($(this).is(":checked")) {
var isAllChecked = 0;
$(".inner").each(function() {
if (!this.checked)
isAllChecked = 1;
});
if (isAllChecked == 0) {
$(".outer").prop("checked", true);
}
} else {
$(".outer").prop("checked", false);
}
});
ul {
list-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>
<input type="checkbox" id="out1" class="outer">
<label for="out1">Checkbox Out 1</label>
</li>
<ul>
<li>
<input type="checkbox" id="inner1" class="inner">
<label for="out1">Checkbox Inner 1</label>
</li>
<li>
<input type="checkbox" id="inner2" class="inner">
<label for="out1">Checkbox Inner 2</label>
</li>
<li>
<input type="checkbox" id="inner3" class="inner">
<label for="out1">Checkbox Inner 3</label>
</li>
</ul>
<li>
<input type="checkbox" id="out2" class="outer">
<label for="out1">Checkbox Out 2</label>
</li>
<ul>
<li>
<input type="checkbox" id="inner4" class="inner">
<label for="out1">Checkbox Inner 4</label>
</li>
<li>
<input type="checkbox" id="inner5" class="inner">
<label for="out1">Checkbox Inner 5</label>
</li>
</ul>
</ul>
Upvotes: 2
Views: 1847
Reputation: 144
Change this:
$('.outer').on('click', function() {
if (this.checked) {
$('.inner').each(function() {
this.checked = true;
});
} else {
$('.inner').each(function() {
this.checked = false;
});
}
});
to this:
$('.outer').on('click',function(){
if(this.checked){
$(this).parent().next("ul").children('li').children('.inner').each(function(){
this.checked = true;
});
}else{
$(this).parent().next("ul").children('li').children('.inner').each(function(){
this.checked = false;
});
}
});
jquery will first select parent then next ul and then all inputs with 'inner' class.
alse change end part of your js code to this:
$('.inner').on('click',function(){
if ($(this).is(":checked")) {
var isAllChecked = 0;
$(this).parent().parent().children('li').children('.inner').each(function() {
if (!this.checked)
isAllChecked = 1;
});
if (isAllChecked == 0) {
$(this).parent().parent().prev('li').children('.outer').prop("checked", true);
}
}
else {
console.log()
$(this).parent().parent().prev('li').children('.outer').prop("checked", false);
}
it will select outer input before your inner classes
Upvotes: 0
Reputation: 177965
Here is a working example
It toggles the children of the next UL and toggles the outer checkbox if all or less than all children are checked
I corrected the invalid HTML to have the ULs as children of the LI and not another UL
$('.outer').on('click', function() {
var chk = this.checked;
$(this).closest("li").find(".inner").each(function() {
this.checked = chk;
});
});
$('.inner').on('click', function() {
var $parent = $(this).closest("ul"),
$inner = $parent.find(".inner"),
$checked = $parent.find(".inner:checked"),
$outer = $parent.closest("li").find(".outer"),
chk = $inner.length === $checked.length ? this.checked : false;
$outer.prop("checked", chk)
});
ul {
list-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>
<input type="checkbox" id="out1" class="outer"><label for="out1">Checkbox Out 1</label>
<ul>
<li><input type="checkbox" id="inner1" class="inner"><label for="out1">Checkbox Inner 1</label></li>
<li><input type="checkbox" id="inner2" class="inner"><label for="out1">Checkbox Inner 2</label></li>
<li><input type="checkbox" id="inner3" class="inner"><label for="out1">Checkbox Inner 3</label></li>
</ul>
</li>
<li>
<input type="checkbox" id="out2" class="outer"><label for="out1">Checkbox Out 2</label>
<ul>
<li><input type="checkbox" id="inner4" class="inner"><label for="out1">Checkbox Inner 4</label></li>
<li><input type="checkbox" id="inner5" class="inner"><label for="out1">Checkbox Inner 5</label></li>
</ul>
</li>
</ul>
Upvotes: 1
Reputation: 337570
Firstly if you correct the HTML so that the child ul
are within the li
of the parent, then this becomes much simpler. When a checkbox is checked you can easily traverse the DOM to find child checkboxes and set their checked
state to match.
Similarly, you can get the checked state of sibling checkboxes. If they are all checked then any parent checkbox should be checked. Something like this:
$(':checkbox').on('change', function() {
// check children
$(this).closest('li').find(':checkbox').prop('checked', this.checked);
// check parent if all children checked
var $ul = $(this).closest('ul');
var $siblings = $ul.find('> li > label > :checkbox');
var allChecked = $siblings.length == $siblings.filter(':checked').length;
$ul.closest('li').find('> label > :checkbox').prop('checked', allChecked);
});
ul {
list-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>
<label><input type="checkbox">Checkbox Out 1</label>
<ul>
<li>
<label><input type="checkbox">Checkbox Inner 1</label>
</li>
<li>
<label><input type="checkbox">Checkbox Inner 2</label>
</li>
<li>
<label><input type="checkbox">Checkbox Inner 3</label>
</li>
</ul>
</li>
<li>
<label><input type="checkbox">Checkbox Out 2</label>
<ul>
<li>
<label><input type="checkbox">Checkbox Inner 4</label>
</li>
<li>
<label><input type="checkbox">Checkbox Inner 5</label>
</li>
</ul>
</li>
</ul>
Note this completely negates the need for any unique id
attributes, as the logic relies on the DOM structure and the label
elements have been moved to wrap the checkbox they are related to. The inner
and outer
class attributes have also been removed as they become redundant when nesting the ul
/li
correctly.
Upvotes: 4
Reputation: 4122
I modified your question with a working one.
Just replace $(".inner").each
with $(this).parent().next().find('li input').each
or another correct selector.
$('.outer').on('click', function() {
if (this.checked) {
$(this).parent().next().find('li input').each(function() {
this.checked = true;
});
} else {
$(this).parent().next().find('li input').each(function() {
this.checked = false;
});
}
});
$('.inner').on('click', function() {
if ($(this).is(":checked")) {
var isAllChecked = 0;
$(".inner").each(function() {
if (!this.checked)
isAllChecked = 1;
});
if (isAllChecked == 0) {
$(".outer").prop("checked", true);
}
} else {
$(".outer").prop("checked", false);
}
});
ul {
list-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>
<input type="checkbox" id="out1" class="outer">
<label for="out1">Checkbox Out 1</label>
</li>
<ul>
<li>
<input type="checkbox" id="inner1" class="inner">
<label for="out1">Checkbox Inner 1</label>
</li>
<li>
<input type="checkbox" id="inner2" class="inner">
<label for="out1">Checkbox Inner 2</label>
</li>
<li>
<input type="checkbox" id="inner3" class="inner">
<label for="out1">Checkbox Inner 3</label>
</li>
</ul>
<li>
<input type="checkbox" id="out2" class="outer">
<label for="out1">Checkbox Out 2</label>
</li>
<ul>
<li>
<input type="checkbox" id="inner4" class="inner">
<label for="out1">Checkbox Inner 4</label>
</li>
<li>
<input type="checkbox" id="inner5" class="inner">
<label for="out1">Checkbox Inner 5</label>
</li>
</ul>
</ul>
Upvotes: 0