Not able to close jQuery UI dialog when opened from a catch block

0

I have built a common error dialog function to get a common look and feel for my dialogs. I call that function from within the $.ajaxSetup.error function without issue. I have one button added through the call on the dialog. My button will close the dialog and the X in the corner will close the window when called from the ajaxSetup.error function.

If I attempt to call this same function from within a catch block within my JS (NOT AN AJAX CALL) the dialog opens without issue but when I click my button to close the dialog I get the following error:

0x800a138f - JavaScript runtime error: Unable to get property '_focusTabbable' of undefined or null reference

Here is the code that generates my dialog:

function __renderDialogOK(data) {

    // This call renders the div to be displayed within
    // the dialog.
    var divMessage = __renderDialogBase(data);

    $(divMessage).dialog(
        {
            width: __getDialogWidth(),
            resizeable: false,
            modal: true,
            hide: true,
            show: true,
            buttons: [
                {
                    text: "OK",
                    click: function (e) {
                        e.preventDefault();
                        $(this).dialog("close");
                        return false;
                    }
                }
            ],
            open: function (e) {
                $(this).parent().find("button:eq(1)").addClass('ui-state-default');
                $(this).parent().find("button:eq(1)").focus();
                $(this).on("keydown", function (event) {
                    if (parseInt(event.keyCode) === 13) {
                        $(this).parent()
                            .find("button:eq(1)").trigger("click");
                        return false;
                    }

                    if (event.keyCode == 27) {
                        $(this).parent()
                            .find("button:eq(1)").trigger("click");
                        return false;
                    }
                });
            },
            close: function (e) {
                $(this).off("keydown");
            }
        }
    );
}

As you can see in my button I attempt to close the dialog using $(this). I have also tried using a variable outside of the function (global) to store the context returned by the call to $(divMessage).dialog(.

This appears to only be happening within IE11 which is unfortunate for me since my customer has that as their current corporate standard. So finally my question(s).

Is all context lost when you enter a Catch block within JavaScript? Has this issue been exposed previously and I am just not seeing the threads? I have read many of the other threads regarding this similar error message but they don't seem to be as specific as my instance and many of them seem to be because the dialog is not initiated yet. Mine is. The dialog is on the screen. I just can't close it with my button.

javascript
jquery
jquery-ui
dialog
catch-block
asked on Stack Overflow Nov 1, 2017 by pachyderm94 • edited Nov 1, 2017 by Nisse Engström

1 Answer

0

Expanding on my comment, I would examine this:

        open: function (e) {
            $(this).parent().find("button:eq(1)").addClass('ui-state-default');
            $(this).parent().find("button:eq(1)").focus();
            $(this).on("keydown", function (event) {
                if (parseInt(event.keyCode) === 13) {
                    $(this).parent()
                        .find("button:eq(1)").trigger("click");
                    return false;
                }

                if (event.keyCode == 27) {
                    $(this).parent()
                        .find("button:eq(1)").trigger("click");
                    return false;
                }
            });
        }

In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which do provide their own this binding (it remains the this value of the enclosing lexical context).

So, in the open callback, $(this) refers to the object that called open. It is sort of similar to $(e.target). So when we then bind a function via .on() to the keydown event, $(this) is no longer the open callback. It is a reference to the keydown callback.

To avoid confusion you can do different things. Here is what I would try first:

        open: function (e) {
            var $me = $(this);
            var $parent = $(this).parent();
            $parent.find("button:eq(1)").addClass('ui-state-default');
            $parent.find("button:eq(1)").focus();
            $me.on("keydown", function (event) {
                if (parseInt(event.keyCode) === 13) {
                    $parent
                        .find("button:eq(1)").trigger("click");
                    return false;
                }

                if (event.keyCode == 27) {
                    $parent
                        .find("button:eq(1)").trigger("click");
                    return false;
                }
            });
        }

This will help retain the proper reference to the proper objects.

answered on Stack Overflow Nov 3, 2017 by Twisty

User contributions licensed under CC BY-SA 3.0