I was working on a modal component in Angular and was trying to toggle a class state on a custom input checkbox on clicking on the label, but it didn't work, I thought it was something with material or else with Angular, but also tried with plain HTML and vanilla JS and it does not allow to change or toggle a class in the label. How could this be? Is there something I am missing with the label click behavior? If you click directly on the input it adds the class 'active' but if clicked the 'M' it doesn't. I am hiding the input from the view since I am styling it to look different.
Here is a piece of code for trying here:
window.addEventListener('load', function() {
let elems = document.querySelectorAll('.form-check-label');
elems.forEach((e) => e.addEventListener('click', function() {
console.log(e.classList);
}, false));
}, false);
function checkInput(elem) {
let checkMark = elem.querySelector('input');
checkMark.checked = !checkMark.checked;
}
.form-check-label {
cursor: pointer;
}
<label
onClick = "this.classList.toggle('active');"
class="form-check-label"
for="Monday">
<input
class="form-check-input"
type="checkbox"
id="Monday"
value="Monday" />
<span class="day-week">
M
</span>
</label>
<br />
<br />
<div
onClick = "this.classList.toggle('active');checkInput(this);"
class="form-check-label"
>
<input
class="form-check-input"
type="checkbox"
value="Monday" />
<span class="day-week">
M
</span>
</div>
If I change the label for a div, then it works. You can check the class state change in the browser console.
This is a interesting case which seems to be related to the behaviour of input
controlled by label
. It can be observed that the click
on label
generate actually 2 click
events, first coming from span
and second (which seems to be a browser synthetic event nevertheless "real") from input
, which sets the focus on input
element, this is most obvious when using a text
type input
. So, the first click
sets the class while the second removes it, that happens almost instantaneous.
As a simple solution is to discard the click
event generated by input
with event.stopPropagation()
, although it will disable a real click on checkbox
:
window.addEventListener('load', function() {
let elems = document.querySelectorAll('.form-check-label');
elems.forEach((e) => e.addEventListener('click', function() {
console.log(e);
}, false));
}, false);
function checkInput(elem) {
let checkMark = elem.querySelector('input');
checkMark.checked = !checkMark.checked;
}
.form-check-label {
cursor: pointer;
}
<label
onClick = "this.classList.toggle('active');"
class="form-check-label"
for="Monday">
<input
onClick = "event.stopPropagation();"
class="form-check-input"
type="checkbox"
id="Monday"
value="Monday" />
<span class="day-week">
M
</span>
</label>
<br />
<br />
<div
onClick = "this.classList.toggle('active');checkInput(this);"
class="form-check-label"
>
<input
class="form-check-input"
type="checkbox"
value="Monday" />
<span class="day-week">
M
</span>
</div>