I am trying to create an achievement tracker that when you click a checkbox it will update a number on how many you have completed in that section. But how I have it implemented now the number only updates on one of the div blocks.
HTML
<div class="card-body">
<div class="heading">
<h2>Endings</h2>
<p><span id="achievement-complete">0</span> / 2</p>
</div>
<ul>
<li id="achievement_7_0">
<div class="card-content">
<input type="checkbox" id="item_7_0" class="sum" value="1" />
<label class='strikethrough' for="item_7_0">
Ending 1
</label>
</div>
</li>
<li id="achievement_7_1">
<div class="card-content">
<input type="checkbox" id="item_7_1" class="sum" value="1" />
<label class='strikethrough' for="item_7_1">
Ending 2
</label>
</div>
</li>
</ul>
</div>
<div class="card-body">
<div class="heading">
<h2>All Achievements</h2>
<p><span id="achievement-complete">0</span> / 1</p>
</div>
<ul>
<li id="achievement_8_0">
<div class="card-content">
<input type="checkbox" id="item_8_0" class="sum" value="1" />
<label class='strikethrough' for="item_8_0">
All Achievements
</label>
</div>
</li>
</ul>
</div>
Javascript
var input = document.getElementsByClassName('sum'),
total = document.getElementById('achievement-complete');
for (var i = 0; i < input.length; i++) {
input[i].onchange = function () {
var add = this.value * (this.checked ? 1 : -1);
total.innerHTML = parseFloat(total.innerHTML) + add
// console.log(add);
}
}
Here I would like it to call a js function in each div block with class="card-body" and update the span with class="achievement-complete" with the new total of achievements completed.
2
Answers
If you wrap your markup in a container element you can use event delegation to capture event from its child elements as they "bubble up" the DOM. Just attach one listener to that container rather than many listeners to many elements.
Then you can get the
checked
status from the element that fired the event, find theclosest
element with acard-body
class, and use that to find the its child element with theachievement-complete
class (note: this is a change to your markup where you’ve usedid
– ids must be unique in a page).Then grab that element’s text, coerce it to an integer, and update it – adding one if the
checked
status istrue
, and subtracting one if it’sfalse
.Additional documentation
addEventListener
Destructuring assignment
matches
It works for me.