6

When binding to a click event for a checkbox input, the checkbox is already toggled by the time my event handler runs and, more oddly, the toggle is reversed after my event handler runs if I specify event.preventDefault();

<input id="foo" type="checkbox"/>

function clicked(evt) {
   alert(document.getElementById('foo').checked);
   evt.preventDefault();
}

document.getElementById('foo').addEventListener('click',clicked);

[tested in chrome and firefox]

JSFiddle for that code

The alert will respond "true" (or the opposite state of the checkbox pre-click). After you dismiss the alert, the checkbox toggles back.

So, I guess the questions are,

What is the actual default event being prevented? Am I wrong in assuming my event handler should be running before the state is changed? Is there a way to legitimately intercept a checkbox click?

And why in the world is the preventDefault causing the re-toggling the checkbox?

jsoverson
  • 1,695
  • 1
  • 12
  • 17
  • Weird thing is also that if you swap the two lines inside `clicked`, you get the same result. So it isn't until *after* the alert that it actually prevents the default. http://jsfiddle.net/pimvdb/NHwXs/3/ – pimvdb Sep 15 '11 at 17:42
  • @pimvdb - That's because `evt.prevntDefault()` toggles a flag and can be called anywhere from within an event handler. It does not have to appear at the end of the call. It controls whether or not the default handler occurs *after* the newly bound one finishes. – g.d.d.c Sep 15 '11 at 17:45
  • You can prevent checking by canceling `mousedown` instead. – Hemlock Sep 15 '11 at 17:47
  • Off-topic: it's good to provide 3rd parameter for addEventListener for backward compatibility: https://developer.mozilla.org/en/DOM/element.addEventListener – jakub.g Sep 15 '11 at 17:50

1 Answers1

9

The actual default event being prevented is the click event. The misunderstanding probably occurs because you are thinking of the event as firing after the actual click has been fully processed (i.e. the checkbox has been toggled) while in reality the event model stipulates that the handler fires while the event is being processed.

If it helps, another model I 've found useful in explaining how it all works is the database transaction model: think of your event handler as being invoked as part of a transaction, inside which the checkbox has already been toggled.

  • If you read the state of the checkbox, you will find it toggled (the "write" has been sent to the database).
  • However, you can still decide to rollback the transaction (in which case the write is undone and the checkbox is toggled back to its original value).
Jon
  • 428,835
  • 81
  • 738
  • 806
  • Thanks, that's a pretty core concept that I'm surprised I was able to skirt around for so long. – jsoverson Sep 15 '11 at 22:27
  • It is easy to imagine an implementation that renders the observed behavior. However, I'd offer that this is counter-intuitive. Sticking with your example, imagine if I were to begin a transaction, perform an `INSERT`, then perform a `SELECT` that validated the `INSERT`, then roll back the transaction when validation fails. This is wasteful. One could simply perform the `SELECT` first, perform validation, then perform the `INSERT`. There are situations where this isn't possible, necessitating a transaction. I don't believe this is one of those situations. – crush Jan 17 '14 at 21:20
  • I'm not sure "transactional" explanation given here agrees with the [official standard](https://www.w3.org/TR/DOM-Level-3-Events/#event-flow-default-cancel). The fact is simply that for *some* selected events the default action gets carried out *before* the event is dispatched and the event listeners get executed and `preventDefault()` will then cause the default action to get rolled back once the event listeners are done. – balu Jul 28 '21 at 12:35
  • (continued) This does not seem to be very common, though: "Default actions are usually performed after the event dispatch has been completed, but in exceptional cases they may also be performed immediately before the event is dispatched." Note that the transactional description only fits those "exceptional cases". – balu Jul 28 '21 at 12:36