简体   繁体   中英

Why does preventDefault on parent element disable programmatically checking child checkbox on click?

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>

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>

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM