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.