Reputation: 349
Here is my code :
It actually count checked checkboxes and write it inside <span class="counter"></span>
. This code works on Firefox, but not on Chrome.
On Chrome, the .select_all check all checkboxes I want, but doesn't update the counter. Actually counter get updated when I uncheck the .select_all, which is weird.
IMPORTANT FACT: I don't want to count the .Select_all checkboxes inside my .counter
jQuery(document).ready(function($){
$(function() {
$('#general i .counter').text(' ');
var generallen = $("#general-content input[name='wpmm[]']:checked").length;
if(generallen>0){$("#general i .counter").text('('+generallen+')');}else{$("#general i .counter").text(' ');}
})
$("#general-content input:checkbox").on("change", function() {
var len = $("#general-content input[name='wpmm[]']:checked").length;
if(len>0){$("#general i .counter").text('('+len+')');}else{$("#general i .counter").text(' ');}
});
$(function() {
$('.select_all').change(function() {
var checkthis = $(this);
var checkboxes = $(this).parent().next('ul').find("input[name='wpmm[]']");
if(checkthis.is(':checked')) {
checkboxes.attr('checked', true);
} else {
checkboxes.attr('checked', false);
}
});
});
});
EDIT: Here is a example document of the code : http://jsfiddle.net/8PVDy/1/
Upvotes: 29
Views: 108420
Reputation: 9691
You can use a function to update the counter :
function updateCounter() {
var len = $("#general-content input[name='wpmm[]']:checked").length;
if(len > 0){
$("#general i .counter").text('('+len+')');
} else {
$("#general i .counter").text(' ');
}
}
and call this function when a checkbox's state is changed (including the selectAll checkboxes)
Here is an updated jsFiddle : http://jsfiddle.net/8PVDy/4/
Upvotes: 64
Reputation: 113
What I found missing in all above answers is an explanation about how to listen to clicks in an efficient way since the question is tightly coupled with onChange event. Another thing is that question doesn't specify whether the code should be only in Jquery I think that adding vanilla JS solution should be a good idea.
Here's the HTML list of checkboxes the I will be counting. I have approched the question in a little bit more generic way, to make it easier to apply in different conditions. I plan to count checkboxes globally and per each section.
<div class="wrapper">
<section class="list list-1">
<label for="id-11"><input type="checkbox" id="id-11"></label>
<label for="id-12"><input type="checkbox" id="id-12"></label>
<label for="id-13"><input type="checkbox" id="id-13"></label>
<label for="id-14"><input type="checkbox" id="id-14"></label>
<label for="id-15"><input type="checkbox" id="id-15"></label>
<label for="id-16"><input type="checkbox" id="id-16"></label>
<label for="id-17"><input type="checkbox" id="id-17"></label>
<label for="id-18"><input type="checkbox" id="id-18"></label>
<label for="id-19"><input type="checkbox" id="id-19"></label>
<label for="id-110"><input type="checkbox" id="id-110"></label>
<span class="list-score">Section 1: <span class="number">0</span></span>
</section>
<section class="list list-2">
<label for="id-21"><input type="checkbox" id="id-21"></label>
<label for="id-22"><input type="checkbox" id="id-22"></label>
<label for="id-23"><input type="checkbox" id="id-23"></label>
<label for="id-24"><input type="checkbox" id="id-24"></label>
<label for="id-25"><input type="checkbox" id="id-25"></label>
<label for="id-26"><input type="checkbox" id="id-26"></label>
<label for="id-27"><input type="checkbox" id="id-27"></label>
<label for="id-28"><input type="checkbox" id="id-28"></label>
<label for="id-29"><input type="checkbox" id="id-29"></label>
<label for="id-210"><input type="checkbox" id="id-210"></label>
<span class="list-score">Section 2: <span class="number">0</span></span>
</section>
<section class="list list-3">
<label for="id-31"><input type="checkbox" id="id-31"></label>
<label for="id-32"><input type="checkbox" id="id-32"></label>
<label for="id-33"><input type="checkbox" id="id-33"></label>
<label for="id-34"><input type="checkbox" id="id-34"></label>
<label for="id-35"><input type="checkbox" id="id-35"></label>
<label for="id-36"><input type="checkbox" id="id-36"></label>
<label for="id-37"><input type="checkbox" id="id-37"></label>
<label for="id-38"><input type="checkbox" id="id-38"></label>
<label for="id-39"><input type="checkbox" id="id-39"></label>
<label for="id-310"><input type="checkbox" id="id-310"></label>
<span class="list-score">Section 3: <span class="number">0</span></span>
</section>
<span class="total-score">Total: <span class="number">0</span></span>
</div>
and here's the JS markup, that listens to all clicks inside the .wrapper
div and counts selected inputs in the context of the .wrapper
and each .list
section.
const total = document.querySelector('.total-score .number')
document.querySelector('.wrapper').addEventListener('change', function(event) { // First we apply the ONLY one listener to do the listening for us - we don't need listener on each checkbox
const numberAll = this.querySelectorAll('input[type="checkbox"]:checked').length // We count all selected inputs in side the main wrapper.
total.innerHTML = numberAll // We update the total counter
const list = event.target.closest('.list') // We look and cache the closest section, wrapping the clicked checkbox element
const numberList = list.querySelectorAll('input[type="checkbox"]:checked').length // Once found, we start to count the number of selected checboxes under the section
list.querySelector('.list-score .number').innerHTML = numberList // We update the sectiona relevant counter
})
Here's the live example in the JS fiddle: https://jsfiddle.net/mkbctrlll/yak4oqj9/159/
In Vanilla JS you have to be aware that applying the change
listener to each checkbox is much slower solution. Instead you should make use of so called event delegation and apply the listener to the wrapping element or even to whole document.
Here you can check it by yourself, how much slower is listening to change per each input in your list:
https://jsperf.com/change-listener-on-each-vs-event-delegation/1
The code for the slower option (just to compare):
document.querySelector('.wrapper').addEventListener('change', function() {
const numberAll = this.querySelectorAll('input[type="checkbox"]:checked').length
total.innerHTML = numberAll
})
document.querySelectorAll('.list').forEach((list) => {
list.addEventListener('change', function() {
const numberAll = this.querySelectorAll('input[type="checkbox"]:checked').length
this.querySelector('.list-score .number').innerHTML = numberAll
})
})
and my solution in jQuery:
$('.wrapper').change(function() {
const numberAll = $(this).find('input[type="checkbox"]:checked').length
total.innerHTML = numberAll
const $list = $(event.target).closest('.list')
const numberList = $list.find('input[type="checkbox"]:checked').length
$($list.find('.list-score .number')).html(numberList)
})
P.S. I tried adding jQuery solution to the benchmark too, but it's performance seemed to be fake, so I decided to go without it.
Upvotes: 1
Reputation: 1693
you can do it this way
$(document).ready(function(){
$('input[type="checkbox"]').click(function(){
alert($('.test:checked').length);
});
});
HTML i used
<input type="checkbox" name="test" class="test" value=""/>
<input type="checkbox" name="test" class="test" value=""/>
<input type="checkbox" name="test" class="test" value=""/>
<input type="checkbox" name="checkAll" class="checkAll" value=""/>
Hope this helps
Upvotes: 11
Reputation: 1246
Modified the select all-handler to trigger the onchange function for the sub-category checkboxes like this
$(function() {
$('.select_all').change(function() {
var checkthis = $(this);
var checkboxes = $(this).parent().next('ul').find("input[name='wpmm[]']");
if(checkthis.is(':checked')) {
checkboxes.attr('checked', true);
} else {
checkboxes.attr('checked', false);
}
// make sure to trigger the onchange behaviour for the checkboxes
$("#general-content input:checkbox").change();
});
})
I seem to remember that there is a prettier way to trigger them, but can't find it
Upvotes: 0
Reputation: 2984
Try this.
$('.select_all').change(function() {
var num = $(this).find("input[name='wpmm[]']:checked").length;
$("#general .counter").html(num);
});
Upvotes: 0
Reputation: 388446
For updating the checked status use the jQuery.prop() function
Code:
$(function(){
$('#general i .counter').text(' ');
var fnUpdateCount = function() {
var generallen = $("#general-content input[name='wpmm[]']:checked").length;
console.log(generallen,$("#general i .counter") )
if (generallen > 0) {
$("#general i .counter").text('(' + generallen + ')');
} else {
$("#general i .counter").text(' ');
}
};
$("#general-content input:checkbox").on("change", function() {
fnUpdateCount();
});
$('.select_all').change(function() {
var checkthis = $(this);
var checkboxes = $("#general-content input:checkbox");
if (checkthis.is(':checked')) {
checkboxes.prop('checked', true);
} else {
checkboxes.prop('checked', false);
}
fnUpdateCount();
});
});
Demo: Fiddle
Upvotes: 2