Why is tab keypress causing focus change also triggering keyup event?
Asked Answered
A

2

1

Pressing the tab key which triggers a focus change is also received by the input receiving the focus as a keyup.

a: <input type='text'/><br/>
b: <input type='text' onkeyup='alert("wtf?")'/><br/>

http://jsfiddle.net/59SnP/

As my control also uses tab (not in the example), I would want the focus related keyup event being consumed (but I want to receive other non-focus-change related tab events). I tried to research the rationale behind the current behavior but found nothing. The question: Where is this current behavior specified (event not consumed by focus change), and what would be a cross-browser workaround to force consuming it. Thx.

Antony answered 12/3, 2014 at 9:20 Comment(1)
The keydown happened on the first input, and the keyUp happened on the second because immediately following the keydown the focus changed to the second input.Unroll
M
1

You can try this. I changed your keyup event in your input :

<input type='text' onkeyup="if(!tabPressed){ alert('This is it !'); }"/>

And I added a little event handler which will raise a flag when the tab button is pressed :

var tabPressed = false;
document.addEventListener('keydown', function (e) {
    if(e.keyCode == 9) {
        tabPressed = true;   
    } else {
        tabPressed = false;
    }
}, false);
Margertmargery answered 12/3, 2014 at 10:12 Comment(1)
That's it, the base concept at least. The false parameter on addEventListener is not reqed as that is the default value. Two things needed is: 1: resetting tabPressed in the inputs onKeyup, cause the key events happening inside the input wont bubble up to document. 2: calling e.stopImmediatePropagation() in the handler in the input, so other event handlers wont receive the false tab event...Antony
A
0

Based on Nathan's insight, here is a fully working example:

// First part of Nathan's HACK (set a sentinel when a focus changing tab has happened)
var tabPressed = false;
// remove this listener to break the functionality
$(document).on("keydown", function (e) {
    if(e.keyCode == 9) {
        tabPressed = true;   
    } else {
        tabPressed = false;
    }
});

// The listener on the client input that would kill the keyup tab event upon focus change
$("#magic").on("keyup", function(e) {
    if (tabPressed && e.keyCode==9) {
        tabPressed = false; // reset the sentinel
        e.stopImmediatePropagation()
        e.preventDefault()
    }
})

And here is the second part, which is a simple skeleton of something meaningful. We disable TAB inside the input, and log it as we do with other keyups:

$("#magic").on("keydown", function(e) {
    if (e.keyCode==9) {
        e.preventDefault()
        e.stopPropagation()
    }
})

$("#magic").on("keyup", function(e) {
    $(this).val($(this).val() + " " + e.keyCode)
    e.stopPropagation()
    e.preventDefault()
})

The HTML backing the story is as simple as:

a: <input type='text'/><br/>
b: <input type='text'/><br/>
c: <input type='text' id='magic'/><br/>

If you want to play with it, here it is on jsfiddle

NOTE: This still is not the perfect solution, the sentinel is just reset inside the control, so if a tabpress moving the focus does not activate our input, the sentinel stucks, and the first event will be swallowed.. So here is an example of wrong behaviour:

  1. Click on input A
  2. Press TAB (focus moves to input B, tabPressed becomes true)
  3. Click on input C
  4. Press TAB (it is eaten up as sentinel is true)
  5. Press TAB (now it goes through)

Still it is slightly better to have to press TAB twice as to have something happening automatically, wo user control...

Antony answered 12/3, 2014 at 19:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.