Consider this sample code:
<span>
<input type="checkbox">
</span>
$('span').click(function(e) {
e.preventDefault();
$(':checkbox')[0].checked = true;
});
Fiddle
From my knowledge, this should happen:
preventDefault()
should prevent the checkbox from being checked by the browser's default behavior, even if the event handler is attached above in the DOM hierarchy. This part works correctly..checked = true
should work as, I believe, it should be independent of the browser's default action for the event which I've cancelled. This part seems buggy, as if the preventDefault()
was affecting it -- remove the preventDefault()
and it works as intended.What's the actual reason why the checkbox stays always unchecked?
I've tested on Chrome 33 and Firefox 27, so this doesn't seem to be a browser bug.
This question is mostly due to curiosity to extend my DOM/Event model knowledge. I don't want workarounds, but rather I want to know why this example fails.
The preventDefault() method cancels the event if it is cancelable, meaning that the default action that belongs to the event will not occur. For example, this can be useful when: Clicking on a "Submit" button, prevent it from submitting a form.
Event.preventDefault() The preventDefault() method of the Event interface tells the user agent that if the event does not get explicitly handled, its default action should not be taken as it normally would be.
There is no opposite method of event. preventDefault() to understand why you first have to look into what event. preventDefault() does when you call it. Underneath the hood, the functionality for preventDefault is essentially calling a return false which halts any further execution.
Given your HTML:
<span>
<input type="checkbox">
</span>
and your code:
$('span').click(function(e) {
e.preventDefault();
$(':checkbox')[0].checked = true;
});
Event bubbling is your issue here.
When clicking the checkbox
, the click event is propagated to the span
. e.preventDefault()
is the called on the event object propagated from the checkbox
.
Hence preventDefault()
is execute against the checkbox
itself, preventing it from being checked.
Ones the click event of the checkbox
is "cancelled" by means of preventDefault
it will stay cancelled until completion of the event flow. (See bottom of answer for more details on that)
If you apply some styling to the span you notice that clicking around the checkbox
your code works as expected but clicking on the checkbox
itself replicates your issue due to the above mentioned.
DEMO - Original Fiddle + styles. Clicking span
is fine, checkbox
is not
According to the MDN documentation on preventDefault():
Calling
preventDefault
during any stage of event flow cancels the event, meaning that any default action normally taken by the implementation as a result of the event will not occur.
The DOM Level 2 Spec also notes:
If an event is cancelable, the
preventDefault
method is used to signify that the event is to be canceled, meaning any default action normally taken by the implementation as a result of the event will not occur. If, during any stage of event flow, the preventDefault method is called the event is canceled.
The DOM Level 3 Events Spec notes under Example 5:
The default action associated with the
click
event on<input type="checkbox">
elements toggles thechecked
IDL attribute value of that element. If theclick
event's default action is cancelled, then the value is restored to its former state.
Wrapping part of the code in a setTimeout
does the trick, as you can see here http://jsfiddle.net/y7C77/
$('span').click(function(e) {
e.preventDefault();
setTimeout(function () {
$('input').prop('checked', true);
}, 1);
});
preventDefault()
cancels the default action, and I think that it's able to cancel it even if you manually do what the browser would do (in this case: altering the checked
property).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With