2

http://jsfiddle.net/NsRyr/1/

I am totally stumped on this. Here's what I'm trying to do : I have a div element (call it #keys) that I'm using to handle keypress events.

HTML:

<div id="#keys" tabindex="1">Focus</div>

JS:

$('#keys').keydown(function () {
    $('#log').append('*'); // just note that an event happened
});

This works as expected -- as long as #keys is focused, I can receive keypress events and respond to them. In addition, I can set focus to other div elements and the keypress events will no longer be handled by #keys. I can then re-focus the div (e.g., by clicking on it directly, or by responding to a click event on another DOM element) and keypress events are handled as I expect.

So far, so good. The problem that I've come across is that if I focus an input element and then try to re-focus #keys by setting a blur handler that's activated after tabbing away from the input, the #keys div does not receive focus ! It works fine if I blur away from the input by clicking, but not if I use the keyboard.

$('#input').blur(function () {
    $('#log').append('blur'); // note that a blur happened
    $('#keys').focus();
});

I think the essence of this question is, why doesn't my blur handler on #input seem to work properly when tabbing away from the input (but it does work properly when clicking away) ? Is this just a browser quirk ? (I am using Chrome 30.0.1599.101 on Mac OS.)

This is my first SO question regarding JS, so please let me know what additional detail I can provide to describe the situation.

(Edit : Interestingly, it seems to work fine if I shift-tab away from #input. Still confused what's happening here ; appears to be some sort of tabindex-related issue ?)

lmjohns3
  • 7,422
  • 5
  • 36
  • 56
  • Based on @Evan's answer, it does seem like my question is a duplicate of http://stackoverflow.com/a/11380447/2280630 -- at least, the answers are the same ! I feel like this one might be more easily searchable because it has more text, but I would be ok with closing. Any opinions ? – lmjohns3 Oct 26 '13 at 22:22

1 Answers1

4

I don't have commenting privileges yet, so I'll have to answer, but please mods should change this, because it's basically a duplicate.

Here's the fix to your fiddle: http://jsfiddle.net/NsRyr/3/

The issue (as described in this answer) is that the blur event fires before the change is done, so the focus needs to be sent down the stack to happen after. Adding a timer deals with the issue.

The line I changed was:

setTimeout($('#keys').focus.bind($('#keys')), 0);

That makes it so it'll wait until the new focus event is completed before firing off the handler.

Community
  • 1
  • 1
Evan
  • 825
  • 4
  • 14
  • Thanks! By the way lmjohns3, please don't actually just use the bind thing there that calls the jQuery object again. It's an ugly quick fix. (Once created, jQuery objects should be assigned to variables, not recreated.) – Evan Oct 26 '13 at 22:12
  • Interesting. This actually does seem to work, but afterwards any key that I press causes `#input` to receive focus again. Perhaps worthy of another question. – lmjohns3 Oct 26 '13 at 22:15
  • @EvanSeehausen so I should use `var el = $('#keys'); setTimeout(el.focus.bind(el), 0);` instead ? – lmjohns3 Oct 26 '13 at 22:16
  • The standard practice with jQuery objects is to do something like `var $keys = $('#keys')`. You could just use `keys` too, but I'd avoid `el`, because it's not really (just) an element. – Evan Oct 26 '13 at 22:18