jqueryjquery-uijquery-ui-dialog

Focusout is triggered twice


I have a textbox and a Jquery UI dialog. When a user is done typing into the textbox and presses Enter, I want to display the dialog. In order to accomplish that I use the following code:

$(document).ready(function () {
    var helpDial = $('#helpDialog');
    var input = $('#helpSearch');

    helpDial.dialog({
        width: 800,
        autoOpen: false,
        modal: true,
        title: "Templates",
        position: [165, 158]
    });

    input.focusin(function () {
        helpDial.dialog('close');
    }).focusout(function () {
        helpDial.dialog('open');
    }).on('keypress', function (e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if (code == 13) {
            input.focusout();
            return false;
        }
    });
});

<input id="helpSearch" />
<div id="helpDialog"></div>

http://jsfiddle.net/7Fpm4/1

The problem is that when I press Enter, the focusout is called twice, one from the input.focusout() and the second time right after the helpDial.dialog('open') in the focusout event handler. This causes two background overlays to be created, and when I close the dialog, one overlay remains visible.

What am I doing wrong? Is there a better way to handle this scenario -- 'an enter pressed in a textfield opens a jQuery dialog'. Thanks.


Solution

  • The only way to prevent an event from firing is to unbind the event handler. Or, depending on the situation, take differential action based on information available at the time the event fires.

    The focusout event is triggered any time the element loses the focus. In this case, every time the user clicks on the textbox, a focusin event is triggered. As soon as the cursor leaves the textbox (which happens when the dialog box is opened), the focusout event is triggered.

    The problem with your code is that you forcibly call the focusout event, and then the focusout event is called naturally when you open the dialog. So, change your code as follows:

    $(document).ready(function () {
        var helpDial = $('#helpDialog');
        var input = $('#helpSearch');
    
        helpDial.dialog({
            width: 800,
            autoOpen: false,
            modal: true,
            title: "Templates",
            position: [165, 158]
        });
    
        input.on('focusin', function () {
            input.on("focusout", textboxFocusOut);
        }).on('keypress', function (e) {
            var code = (e.keyCode ? e.keyCode : e.which);
            if (code == 13) {
                textboxFocusOut();
            }
        });
    
        function textboxFocusOut() {
            input.off("focusout", textboxFocusOut);
            helpDial.dialog('open');                
        }
    
    });
    

    http://jsfiddle.net/8L7EL/1/

    What this code is doing is binding a function to focusout within the focusin handler. If the user navigates away from the textbox, the focusout event handler will be called, which immediately unbinds the focusout event (to prevent binding the function multiple times). If the user hits the enter key, then the function is called manually, which removes the focusout event handler before opening the dialog to prevent triggering the focusout event from firing automatically when the dialog opens.