5

What I'm doing

In some part of the code, I have a listener on focusin events, and in another part programmatically set the focus on an input. On Chrome, Safari, Firefox the event listener is called once, but on IE (including IE10), it is called twice. I register the listener with jQuery's .on() and set the focus with jQuery's .focus(). See below for the full source of an example that shows this behavior, and if you wish, you can run that example.

Questions

  1. Even when not using jQuery, IE is firing focusin twice. And it does so only when the focus is set programmatically, not when users tab or click on the field. Why? Is it just an IE bug, or does IE have a good reason for behaving this way?
  2. Whether it is a IE bug or not, shouldn't jQuery iron out the difference between IE and other browsers here? In other words, is not doing so a jQuery bug?
  3. How would you work around this? (I.e. so I can have code that runs just once per focus, whether the focus is set programmatically or by users.)

Full source

<!DOCTYPE html>
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
        <script>
            $(function() {
                $('input').on('focusin', function() {
                    var c = $('#count');
                    $('#count').text(1 + parseInt(c.text()));
                    console.log('focusin');
                });
                $('input').focus();
            });
        </script>
    </head>
    <body>
        <input>
        <code>focusin</code> received: <span id="count">0</span>.
    </body>
</html>
Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
avernet
  • 30,895
  • 44
  • 126
  • 163

2 Answers2

3

This is definitely an IE issue. From the JQuery 1.9 upgrade guide:

Unfortunately, all versions of Internet Explorer (6 through 10) fire focus events asynchronously. When you .trigger("focus") in IE, jQuery won't "see" the async focus event which will occur later, so it fires one of its own to ensure that a focus event always occurs as described above. This causes two calls to the event handler. To avoid this double-call--but risk that the event handler is not called at all--use the DOM focus method directly, e.g., $("selector").get(0).focus().

I used $('input').get(0).focus() and it was not very consistent on the loading of the page. If I move the code to a button, then I consistently got the focusin event firing.

John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • Awesome, thank you. I changed our code to use `$('input').get(0).focus()`, and at least in the case I've been testing this, with the IE I've been using, the focus is set consistently on page load. Now I understand better jQuery's rational, even if I'm not sure I agree that is it a good idea to have this requirement to always have a focus even dispatched on calling `focus()`, even if the control isn't focusable or already has the focus. – avernet Jan 21 '13 at 20:50
  • FYI, this still happened in IE 11. It's so frustrating! – Joshua H Oct 16 '17 at 09:12
1

I have a different solution for this. It is ugly, but works.

  1. Create an own focus_handler() function and bind it to focus event
  2. Unbind focus event before calling .focus() // remember IE will call focus twice here
  3. bind focus_handler to focus event before you need it again (e.g: focusout, click)

This worked for me.