hawkidoki
hawkidoki

Reputation: 349

How to count every checked checkboxes

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

Answers (7)

gabitzish
gabitzish

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

mkbctrl
mkbctrl

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

Roger
Roger

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

Ledhund
Ledhund

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

KBN
KBN

Reputation: 2984

Try this.

$('.select_all').change(function() {
var num = $(this).find("input[name='wpmm[]']:checked").length;
$("#general .counter").html(num);
});

Upvotes: 0

Arun P Johny
Arun P Johny

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

nbrooks
nbrooks

Reputation: 18233

$('input[type="checkbox"]:checked').length

Upvotes: 43

Related Questions