Search code examples
javascriptjquerykeypresskeydownkeyup

jQuery: Getting new value in keydown handler


I came across this question: onKeyPress Vs. onKeyUp and onKeyDown, from where I found that keypress is supposed to fire whenever a character is typed into the text input. I am trying to run this following code. It is supposed to make the input's background yellow the moment its text length exceeds 0, or white the moment it is 0. I can't make it work. If I try to do keydown, I have the following problems:

  1. If I just type one character and let go, the background remains white.

  2. If then, I press backspace, thus clearing that one character, it turns yellow (just opposite of what I want!). If I press any other key now (Alt,Shift) it will turn white again. In fact, if instead of Alt or Shift I type a character, it will still remain white, taking us back to the first problem.

  3. If I type press a character key and keep it pressed, the background remains white for the first character, and turns yellow 2nd character onwards.

If I try keyup only, these are the problems (as expected):

  1. The background doesn't change as long as the keys are kept pressed, even when a character is added to the empty input or the entire text deleted.

If I try keypress, I face the same problems as keydown, even though it is supposed to work.

If I bind 3 handlers for keyup, keydown and keypress (God I am desperate!), almost all problems are solved except problem 3 of keydown: if I type press a character key and keep it pressed, the background remains white for the first character, and turns yellow 2nd character onwards.

How do I solve this problem?

JS:

$(document).ready(function() {

    $("input").bind("keydown", function() {
        if ($(this).val().length == 0) {
            $(this).css('background', 'white');
        } else {
            $(this).css('background', 'yellow');
        }
    });

    $("input").bind("keypress", function() {
        if ($(this).val().length == 0) {
            $(this).css('background', 'white');
        } else {
            $(this).css('background', 'yellow');
        }
    });

    $("input").bind("keyup", function() {
        if ($(this).val().length == 0) {
            $(this).css('background', 'white');
        } else {
            $(this).css('background', 'yellow');
        }
    });

});

HTML:

<input type='text' />

Solution

  • When the keydown event is fired, the character is not yet written to the input box.

    I did some research and it's recommended to use timeout in order to get the behaviour you want. Apparently, during the tiny delay, a change event on the input is fired, and .val() then returns the new content.

    Here's a working code:

    $(document).ready(function () {
        var field = $("input");
    
        field.on("keydown", function (e) {
            setTimeout(function () {
                if (field.val().length == 0) {
                    field.css('background', 'white');
                } else {
                    field.css('background', 'yellow');
                }
            }, 1);
        });
    });
    

    Accompanied by a jsFiddle