Reputation: 2457
A div
element's click event has e.preventDefault()
at the beginning. That makes manually clicking the checkbox input
or it's associated label
inside no longer works.
With the help of some more JavaScript code, manually clicking the label
generates expected results because the checkbox is now programmatically checked/unchecked.
However, manually clicking the checkbox input
still does not work despite the fact that similar JavaScript code for programmatically checking/unchecking has been implemented. Why?
document.querySelector('div').onclick = function (e)
{
e.preventDefault();
if (e.target.tagName.toUpperCase() == 'LABEL')
{
e.target.previousElementSibling.checked = !e.target.previousElementSibling.checked;
}
else if (e.target.tagName.toUpperCase() == 'INPUT')
{
e.target.checked = !e.target.checked;
}
}
<div>
<input id="check" type="checkbox">
<label for="check">Label Text</label>
</div>
Upvotes: 2
Views: 1005
Reputation: 12918
Clicking the label
sets the checked
property as expected because there is no default
action related to the label to be canceled. Clicking the input
sets the property as expected, but due to the default action (toggling the checked property) being prevented it reverts to its previous state.
see: Why does preventDefault on checkbox click event returns true for the checked attribute? for more in depth discussion.
document.querySelector('div').onclick = function (e)
{
e.preventDefault();
if (e.target.tagName.toUpperCase() == 'LABEL')
{
e.target.previousElementSibling.checked = !e.target.previousElementSibling.checked;
}
else if (e.target.tagName.toUpperCase() == 'INPUT')
{
console.clear();
console.log(e.target.checked);
e.target.checked = !e.target.checked;
console.log(e.target.checked);
}
}
<div>
<input id="check" type="checkbox">
<label for="check">Label Text</label>
</div>
Edit
In response to your comment I think the cleanest solution would be to explicitly apply listeners to those elements that you want to control outside of the provided API methods calling stopPropagation()
on them to avoid triggering the parent listeners.
You can then handle whatever logic you need without having to work around artifacts of the outside methods. If you need the parent to listener to run as well you can programmatically activate it after your control logic is finished.
// original API listener
document.querySelector('.container').addEventListener('click', function (e) {
e.preventDefault();
// add container specific code
console.log('clicked div');
});
// your isolated listener
document.querySelector('.checkbox-container').addEventListener('click', function (e) {
e.stopPropagation(); // stop the event from propagating to the parent listener
// add checkbox specific code
console.clear();
console.log('clicked checkbox container');
// even programmatically 'clicking' parent if you need to
e.currentTarget.parentElement.click();
});
.container {
width: 150px;
height: 60px;
background-color: lightgray;
}
.checkbox-container {
display: inline-block;
background-color: aquamarine;
}
<div class="container">
<div class="checkbox-container">
<input id="check" type="checkbox">
<label for="check" >Label Text</label>
</div>
</div>
Upvotes: 1
Reputation: 1628
Prevent default propagates often propagates down to the child. There is a way to stop that from happening by using using event.stopPropagation. Read here to learn more about other useful methods that might help your cause.
https://chunkybyte.medium.com/the-one-with-event-propagation-and-e-preventdefault-part-1-6d84f3c4220
Upvotes: 2