Zero
Zero

Reputation: 738

Keyup event behavior on tab

In this demo, if you place your cursor in the first field and then tab out (without making any changes), the keyup event is fired on the second field. i.e., you are tabbing out of first field and into second field. Is this behavior correct? How can I prevent this from happening? Same applies to shift + tab.

Note:

a) I believe all other keys, printable and non-printable, trigger the keyup event on the first field.

b) The event isn't triggered at all if you keep the tab pressed until it moves out of both fields.

HTML:

<form id="myform">
    <input id="firstfield" name="firstfield" value="100" type="text" />
    <input id="secondfield" name="secondfield" value="200" type="text" />
</form>

jQuery:

jQuery(document).ready(function() {
    $('#firstfield').keyup(function() {
      alert('Handler for firstfield .keyup() called.');
    });
    $('#secondfield').keyup(function() {
      alert('Handler for secondfield .keyup() called.');
    });
});

Upvotes: 20

Views: 19469

Answers (4)

KyleMit
KyleMit

Reputation: 29927

I was recently dealing with this for a placeholder polyfill. I found that if you want to capture the keyup event in the originating field, you can listen to the keydown event and fire the keyup event if a tab was pressed.

Instead of this:

$(this).on({'keyup': function() {
                //run code here
            }
        });

Change to this:

$(this).on({'keydown': function(e) {
                // if tab key pressed - run keyup now
                if (e.keyCode == 9) {
                    $(this).keyup();
                    e.preventDefault;
                }
            },
            'keyup': function() {
                //run code here
            }
        });

Upvotes: 4

Zero
Zero

Reputation: 738

I ended up using this solution:

HTML:

<form id="myform">
    <input id="firstfield" name="firstfield" value="100" type="text" />
    <input id="secondfield" name="secondfield" value="200" type="text" />
</form>

jQuery:

jQuery(document).ready(function () {
    $('#firstfield').keyup(function (e) {
        var charCode = e.which || e.keyCode; // for cross-browser compatibility
        if (!((charCode === 9) || (charCode === 16)))
            alert('Handler for firstfield .keyup() called.');
    });
    $('#secondfield').keyup(function (e) {
       var charCode = e.which || e.keyCode; // for cross-browser compatibility
       if (!((charCode === 9) || (charCode === 16)))
            alert('Handler for secondfield .keyup() called.');
    });
});

This solution doesn't run the alert if the key is tab, shift or both.

Solution: http://jsfiddle.net/KtSja/13/

Upvotes: 2

theftprevention
theftprevention

Reputation: 5213

A key's default action is performed during the keydown event, so, naturally, by the time keyup propagates, the Tab key has changed the focus to the next field.

You can use:

jQuery(document).ready(function() {
    $('#firstfield, #secondfield').on({
        "keydown": function(e) {
            if (e.which == 9) {
                alert("TAB key for " + $(this).attr("id") + " .keydown() called.");
            }
        },
        "keyup": function(e) {
            if (e.which != 9) {
                alert("Handler for " + $(this).attr("id") + " .keyup() called.");
            }
        }
    });
});

This way, if the Tab key is pressed, you can make any necessary adjustments before handling other keys. See your updated fiddle for an exampe.

Edit

Based on your comment, I revamped the function. The JavaScript ended up being a bit complicated, but I'll do my best to explain. Follow along with the new demo here.

jQuery(document).ready(function() {
    (function($) {
        $.fn.keyAction = function(theKey) {
            return this.each(function() {
                if ($(this).hasClass("captureKeys")) {
                    alert("Handler for " + $(this).attr("id") + " .keyup() called with key "+ theKey + ".");
                    // KeyCode dependent statements go here.
                }
            });
        };
    })(jQuery);

    $(".captureKeys").on("keydown", function(e) {
        $("*").removeClass("focus");
        $(this).addClass("focus");
    });
    $("body").on("keyup", "*:focus", function(e) {
        if (e.which == 9) {
            $(".focus.captureKeys").keyAction(e.which);
            $("*").removeClass("focus");
        }
        else {
            $(this).keyAction(e.which);
        }
    });
});

Basically, you give class="captureKeys" to any elements on which you want to monitor keypresses. Look at that second function first: When keydown is fired on one of your captureKeys elements, it's given a dummy class called focus. This is just to keep track of the most recent element to have the focus (I've given .focus a background in the demo as a visual aid). So, no matter what key is pressed, the current element it's pressed over is given the .focus class, as long as it also has .captureKeys.

Next, when keyup is fired anywhere (not just on .captureKeys elements), the function checks to see if it was a tab. If it was, then the focus has already moved on, and the custom .keyAction() function is called on whichever element was the last one to have focus (.focus). If it wasn't a tab, then .keyAction() is called on the current element (but, again, only if it has .captureKeys).

This should achieve the effect you want. You can use the variable theKey in the keyAction() function to keep track of which key was pressed, and act accordingly.

One main caveat to this: if a .captureKeys element is the last element in the DOM, pressing Tab will remove the focus from the document in most browsers, and the keyup event will never fire. This is why I added the dummy link at the bottom of the demo.

This provides a basic framework, so it's up to you to modify it to suit your needs. Hope it helps.

Upvotes: 15

Josh
Josh

Reputation: 44906

It is expected behavior. If we look at the series of events happening:

  1. Press Tab Key while focus is on first text box
  2. Trigger key down event on first text box
  3. Move focus to second text box
  4. Lift finger off tab key
  5. Keyup event is triggered on second text box

Key up is fired for the second text box because that is where it occurs since the focus was shifted to that input.

You can't prevent this sequence of events from happening, but you could inspect the event to see what key was pressed, and call preventDefault() if it was the tab key.

Upvotes: 5

Related Questions