Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Receiving two `focusin` events on focus

Tags:

jquery

focusin

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>
like image 842
avernet Avatar asked Oct 05 '22 07:10

avernet


2 Answers

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.

like image 158
John Koerner Avatar answered Oct 10 '22 03:10

John Koerner


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.

like image 39
Zoltán Rajkai Avatar answered Oct 10 '22 02:10

Zoltán Rajkai