Return a value from window.open

desautelsj picture desautelsj · Sep 11, 2014 · Viewed 58.3k times · Source

We recently discovered that Chrome no longer supports window.showModalDialog which is problematic because our enterprise application uses this method.

There is, apparently, a short term workaround that allows you to restore showModalDialog but it involves modifying the registry which is too complicated (and risky) four our average user. Therefore I'm not a big fan of this workaround.

The long term solution is obviously to remove all calls to this obsolete method and replace them with a convenient jQuery plugin (such as VistaPrint's Skinny Modal Dialog plugin, for example. Other suggestions are welcome by the way).

The typical scenario we use the modal dialog is to ask the user for Yes/No confirmation before executing an action that cannot be undone, ask the user to agree to terms and condition before proceeding, etc. Typically the onclick event on the "Yes" or "Ok" button in the modal dialog looks like this:

window.returnValue = true;
window.close();

Similarly, the "Cancel" or "No" button looks like this:

window.returnValue = false;
window.close();

The fact that we can return a value from the dialog is very convenient because it allows the "parent" window to be notified whether the user has clicked the "Ok" or the "Cancel" button like so:

var options = "center:1;status:1;menubar:0;toolbar:0;dialogWidth:875px;dialogHeight:650px";
var termsOfServiceAccepted = window.showModalDialog(myUrl, null, options);
if (termsOfServiceAccepted) {
    ... proceed ...
}

The last thing I'm going to mention about the showModalDialog is that it works great even when the document displayed in the dialog is from a different domain. It's very common for us to have our javascript running from http://the-client.com but the "Terms of Service" web page is from http://the-enterprise-vendor.com

I need a temporary solution that I can deploy ASAP while we work on the long term solution. Here are my criteria:

  • minimal code change in existing JavaScript
  • the pop up window must be able to return a value to the "parent". Typically this value is a Boolean but it could be any simple type (e.g.: string, int, etc.)
  • solution must work even if the URL of the content is from different domain

Here's what I have so far:

1) Add the following method in my JavaScript:

function OpenDialog(url, width, height, callback)
{
    var win = window.open(url, "MyDialog", width, height, "menubar=0,toolbar=0");
    var timer = setInterval(function ()
    {
        if (win.closed)
        {
            clearInterval(timer);
            var returnValue = win.returnValue;
            callback(returnValue);
        }
    }, 500);
}

As you can see in this method, I try to make the pop up window look as similar to a dialog as possible by hiding the menu and the toolbar, I setup a time every 500 milliseconds to check if the window has been closed by the user and if so, get the 'returnValue' and invoke a callback.

2) replace all calls to showModalDialog with the following:

OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
    if (termsOfServiceAccepted)
    {
        ... proceed ....
    }
});

The fourth parameter to the method is the callback where I check if the user has clicked the "Ok" button before allowing her to proceed.

I know it's a long question but basically it boils down to:

  1. What do you think of the solution I propose?
  2. In particular, do you think I'll be able to get a returnValue from a window that was opened with window.open?
  3. Any other alternative you can suggest?

Answer

Augusto Altman Quaranta picture Augusto Altman Quaranta · Sep 11, 2014

I have two ideas that could help you but the first one is tied to CORS, so you won't be able to use it from different domains at least you can access both services and configure them.

FIRST IDEA:

The first one is related to this native api. You could create on the parent window a global function like this:

window.callback = function (result) {
    //Code
}

As you can see it receives a result argument which can hold the boolean value you need. The you could open the popup using the same old window.open(url) function. The popup's onlick event handler could look like this:

function() {
    //Do whatever you want.
    window.opener.callback(true); //or false
}

SECOND IDEA: Solves the problem

The other idea I got is to use this other native api to trigger an event on the parent window when the popup resolves (better known as cross-document messaging). So you could do this from the parent window:

window.onmessage = function (e) {
    if (e.data) {
        //Code for true
    } else {
        //Code for false
    }
};

By this way you are listening to any posted message on this window, and checking if the data attached to the message is true (the user clicks ok in the popup) or false (the user clicks cancel in the popup).

In the popup you should post a message to the parent window attaching a true or a false value when corresponds:

window.opener.postMessage(true, '*'); //or false

I think that this solution perfectly fits your needs.

EDIT I have wrote that the second solution was also tied to CORS but digging deeper I realized that cross-document messaging isn't tied to CORS