Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change event not fired when keydown event (TAB key) modifies element value

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.

like image 250
Bill Boga Avatar asked Sep 17 '13 19:09

Bill Boga


3 Answers

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.

  1. If you give the element focus and tab off, no change is fired -- no change had occurred since tab doesn't change the field content.
  2. If you give the element focus and type something and tab off, change is fired because during that magical "default actions related to tab" moment, the browser notices the user contributed a change.

Whew!

like image 162
mjk Avatar answered Oct 20 '22 08:10

mjk


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.

like image 35
Two-Bit Alchemist Avatar answered Oct 20 '22 07:10

Two-Bit Alchemist


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).

like image 1
Eli Gassert Avatar answered Oct 20 '22 06:10

Eli Gassert