Steve said:
I think that onChange is what you want. I was tinkering with some
onChange code for RADIO buttons recently, and discovered that onChange
seems to trigger for radio buttons only when they change from unchecked
to checked. There is some sense in this, otherwise you'd often get two
events each time a button was changed (the other one coming from the
button which got unchecked).
onchange is "specified" to fire after the element loses focus and it has
a new value.[1][2]
However, when the control is checkbox or radio, the |checked| state is
usually what determines the "onchange" firing.
But that's only part of the picture.
When a radio or checkbox |checked| property is set in script, onchange
won't fire. Even when calling focus() before and blur() after.
The only way to get onchange to fire is for the user to change it, or to
dispatch a change event on the target programmatically, using
initMouseEvent[3][2]. initMouseEvent has the unusual design of 15
parameter variables. I still haven't memorized the order.
Mozilla has a checkboxstatechange event[4] for XUL that seems to have
leaked into HTML. Probably not the most reliable thing to use in
production apps, and has been filed as a bug[5].
I can't explain the reasoning behind the HTML and DOM specs ignoring
"change" for radio and checkbox. I can, however, demonstrate that the
facts are provable in a very simple demonstration:-
========================================================
<!DOCTYPE html>
<html>
<head>
<title>checkbox onchange firing for programmatic changes</title>
</head>
<body>
<form action="">
<input type="checkbox" name="a" id="a1">
<input type="checkbox" name="a" id="a2">
<input type="checkbox" name="a" id="a3">
</form>
<pre id='monitor'> </pre>
<script type="text/javascript">
document.onchange = function(e) {
text.data += '\n' + e.type + ": " +
e.target.type + "#" + e.target.id;
};
var inputs = document.body.getElementsByTagName('input'),
i = 0,
text = document.getElementById('monitor').firstChild;
var timer = setInterval(function() {
if(!inputs
) {
i = 0;
clearTimeout(timer);
}
var checkbox = inputs;
checkbox.focus();
text.data += "\ncheckbox " + checkbox.id + " focused";
text.data += "\ncheckbox " + checkbox.id + " changed";
checkbox.checked = true;
//checkbox.value = i;
checkbox.blur();
text.data += "\ncheckbox " + checkbox.id + " blurred\n";
i++;
}, 600);
</script>
</body>
</html>
========================================================
Running the example in three browsers (op, ff, saf), the result of
changing the |checked| property via script will not cause a change event
to fire. The output looks like:
| checkbox a1 focused
| checkbox a1 changed
| checkbox a1 blurred
|
| checkbox a2 focused
| checkbox a2 changed
| checkbox a2 blurred
|
| checkbox a3 focused
| checkbox a3 changed
| checkbox a3 blurred
|
| checkbox a1 focused
| checkbox a1 changed
| checkbox a1 blurred
However, change will fire when you, as a user, click the checkbox by
clicking it with your mouse or activating it with the spacebar when it's
focused.
| change: checkbox#a1
| change: checkbox#a2
| change: checkbox#a3
Radio buttons don't fire change when checked programmatically either.
They only fire change on user action.
SO, to answer the OP's question, I think you can use a combination of
polling the event, plus capturing the change event on the object itself.
If supporting IE is concerned, don't use bubbling. Change doesn't bubble
in IE[6].
Garrett
[1] HTML 4.01
http://www.w3.org/TR/REC-html40/interact/scripts.html#h-18.2.3
[2] DOM Events
http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-htmlevents-h3
[3] initMouseEvent
http://developer.mozilla.org/en/DOM/event.initMouseEvent
[4] checkboxstatechange, XUL Planet
http://www.xulplanet.com/references/elemref/ref_EventHandlers.html
[5] Mozilla Bug 335020 "No nice way to watch for checkbox toggle"
https://bugzilla.mozilla.org/show_bug.cgi?id=335020
[6] MSDN: onchange Event
http://msdn.microsoft.com/en-us/library/ms536912(VS.85).aspx