I'm not sure if it's possible, but I'd like to use one unique function to trigger 4 different buttons to count a value (+ and -). But there are four different span values, for example, if I trigger forest it will only add or remove from forest, if I do it for town it will only trigger for town, and so on.
// set inital value to zero
let count = 0;
// select value and buttons
const valueForest = document.querySelector("#valueForest");
const btns = document.querySelectorAll(".btn");
btns.forEach(function (btn) {
btn.addEventListener("click", function (e) {
const styles = e.currentTarget.classList;
if (styles.contains("decrease")) {
count--;
} else if (styles.contains("increase")) {
count++;
} else {
count = 0;
}
if (count > 0) {
valueForest.style.color = "green";
}
if (count < 0) {
valueForest.style.color = "red";
}
if (count === 0) {
valueForest.style.color = "#222";
}
valueForest.textContent = count;
});
});
<div class="scoreDiv">
<h3>Input below the quantity of each tile in the end of the game:</h3>
<div class="scoreItem">
<h4>Forest</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueForest">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Town</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueTown">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Production</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueProduction">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Factory</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueFactory">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
</div>
yes, with event delegation
this way:
const scoreDiv = document.querySelector('div.scoreDiv') // the parent Div
scoreDiv.onclick = e => // get all clicks everywhere upon this parent Div
{
if (!e.target.matches('div.scoreItem > button.btn ')) return // ignore other clicks
let countEl = e.target.closest('div.scoreItem').querySelector('span.value')
, newVal = +countEl.textContent + (e.target.matches('.decrease') ? -1 : +1)
;
countEl.style.color = (newVal > 0) ? 'green' : (newVal < 0) ? 'red' : '#222'
countEl.textContent = newVal;
}
span.value {
display : inline-block;
width : 5em;
text-align : right;
padding-right : .5em;
font-weight : bold;
}
<div class="scoreDiv">
<h3>Input below the quantity of each tile in the end of the game:</h3>
<div class="scoreItem">
<h4>Forest</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueForest">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Town</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueTown">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Production</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueProduction">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Factory</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueFactory">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
</div>
Explanations about
if (!e.target.matches('div.scoreItem > button.btn')) return
First of all the event handler scoreDiv.onclick = e =>
concern everything inside
<div class="scoreDiv">
// everything inside
</div>
So this get any click event in this space is processed by this arrow function.
It could be a click:
on the H3 element
, or one of the span elements
, or any the H4 elements
, everything !
, even the spaces between any elements.
the event [e] have diffrents properties
e.currentTarget
--> is a reference to the caller element (here it is scoreDiv [div.scoreItem])
e.target
--> is a reference to the element where the click happen
for this job we need to do only increment / decrement operations.
that's mean we have to ignore any click event witch is not on the plus or minus buttons.
This 8 buttons are : <button class="btn decrease">-</button>
or <button class="btn increase">-</button>
All this buttons correspond to CSS = div.scoreItem > button.btn
In javascript the code for testing that is
e.target.matches('div.scoreItem > button.btn')
will return a boolean value (true or false)
There is now a strategy: Instead of making a big
if ( e.target.matches('div.scoreItem > button.btn') )
{
//...
// with many lines of code
//until the closing
}
// and then quit the function
and because this is a function we use a Logical NOT (!)
to make a direct return
from function, coded like that:
if (!e.target.matches('div.scoreItem > button.btn')) return
The main interest is to quickly free the event manager in case of another element (present in scoreDiv) have is own click eventHandler.