Given HTML of:
<input type="text" id="test" />
and JavaScript of:
var $test = $('#test');
$test.on('keydown', function(event) {
if (event.keyCode === 9) {
$(event.target).val('change it!');
}
});
$test.on('change', function(event) {
alert('I am not called!');
});
if I type anything in the input and hit the tab, why does the change
event not fire? The keydown
event fires, and updates the value of the input.
If I remove the .val()
call, then change
does fire.
At first, I thought this was a jQuery issue (running 1.9.1), but confirmed the same behaviors occur if I use plain JavaScript.
change
only fires for changes committed by the user. In other words, using JavaScript to change an element's value in the background doesn't fire change
.
Tab doesn't actually change the content of the element; it just switches focus. It's coincidental, in some ways, that you're typing tab to change the element's content (you might as well be pressing a button to update it indirectly, which wouldn't fire change
either).
The DOM spec explains why, in your specific case, if you type and tab, the user input is discarded and no change is fired.
Specifically:
The keyboard events defined in this specification occur in a set order relative to one another, for any given key:
- keydown
- keypress (only for keys which produce a character value)
- Any default actions related to this key
- keyup
When you press the tab key, keydown
is triggered. Boom, your event handler is called! The element content is updated by your script -- no change fired because it's script doing it. The user contributed content is wiped out. Now it's time for the browser to perform the default actions associated with tab: take focus away and see whether the element was changed by the user (to fire onchange). Nope, it was changed by the script! No change
to fire.
Thus, if you remove the val()
line, you'll notice two things.
change
is fired -- no change had occurred since tab doesn't change the field content.change
is fired because during that magical "default actions related to tab" moment, the browser notices the user contributed a change.Whew!
I never did get around to figuring out the why (as the other responders already did), but I did find a solution for you, since you're already using jQuery. Just trigger the change event yourself by using its jQuery method instead of val():
var test = $('#test');
test.on('keydown', function(event) {
if (event.keyCode == 9) {
$(event.target).change(function(){
this.value = 'change it!';
});
}
});
test.on('change', function(event) {
alert('I am not called!');
});
See fiddle.
You're changing the value before the keyup
of the tab. At keyup
the change event would be triggered. But since you changed the value during the keydown
handler, by the time it loses focus, the value is back to what it was previously.
To see this, change your jquery from keydown
to keyup
and you'll see the event fires (and you'll also see the event fires AND THEN the keyup
triggers and changes text back).
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