Tuesday, December 25, 2012

Replace window.showModalDialog with window.open

showModalDialog method supports most of the modern browsers. But in some browsers such as safari browser in iPad does not support showModalDialog method simply because they don’t have a concept of popup windows. So if a system needs to support to view in iPads showModalDialog method needs to be replaced with another method. The closest method is the window.open method, but this method has major limitations comparing to window.showModalDialog method.

The major difference between these two methods is showModalDialog halts the executions of the JavaScript until the dialog box is closed and can get a return value from the opened dialog box when its closing. In contrast window.open just opens a window asynchronously (User can access both the parent window and the opened window). And the JavaScript execution will continue immediately. 

To replace showModalDialog with window.open there is no easy way to do this. But with some limitations window.showModalDialog method can be replaced with window.open method.

To implement the functionality of getting return value from the dialog box normal JavaScript execution has to be divided into two deferent phases.

Phase 1 – JavaScript execution until the dialog box is open.
Phase 2 –JavaScript execution after the return value is been returned from the dialog box. 
Let’s take a simple JavaScript function as follows.

function openNewWindow() {
            var ModalWidth = "100px";
            var ModalHeight = "500px";
            var retValue = window.showModalDialog(urlPath, arrArguments, "dialogWidth:" + ModalWidt +";dialogHeight:" + ModalHeight + ";center:yes;help:no;resizable:no;status:no;scroll:no");

      if (retValue != null || retValue != "") {
             alert(retValue);
        }
        else {
             alert('No value returned');
        }
}

In the above example first of all we need to divide it to two main functions.

Phase 1
Let’s take a simple JavaScript function as follows.

function openNewWindow() {
            var ModalWidth = "100px";
            var ModalHeight = "500px";
            var retValue = window.showModalDialog(urlPath, arrArguments, "dialogWidth:" + ModalWidt +";dialogHeight:" + ModalHeight + ";center:yes;help:no;resizable:no;status:no;scroll:no");
}

Phase 2
function callback(retValue){
    if (retValue != null || retValue != "") {
             alert(retValue);
        }
        else {
             alert('No value returned');
        }
}

The callback function is the function which is going to call when the child window is getting closed. So the child window calls a function in parent window when the window is getting closed.  We can use Jquary unload method to bind a window unload event. So the unload event calls a callback function when the window is getting closed. But there is a limitation here, this window unload event will fires when the full post back occur in the child window. To avoid this, update panels have to be used to implement partial post backs.  The bottom line is, the window unload event should trigger only when the window is actually closing.  Following code lines shows how we can implement the window unload event.

var childWindow = window.open(urlPath,"","toolbar=no, directories=no, location=no, status=yes, menubar=no, resizable=yes, scrollbars=no, width="+Width+", height="+Height);
   
    $(childWindow).unload(function(){
            //We use isOpened propoerty to see whether the "unload" event is being called for the second time.
            //On the first time, isOpened is not defined, so we don't call the callback on that occassion.
            //In the second time, isOpened is defined, so can call the callback function.
            if (childWindow.isOpened == null) {
                childWindow.isOpened = 1;
            }
            else {
                if(callback){
                    callback(childWindow.returnValue);
                }
            }
      });
In this example a parameter called isOpened is used to avoid triggering unload event when the page loads. Here callback is the function which needs to call when the window getting closed and which is in the parent window.

Let’s consider the phase 1 again. In here we need to call the window.open, and also we need to preserve the normal execution of the code as previously in the browsers which showModalDialog supports.


function openNewWindow() {
            var ModalWidth = "100px";
            var ModalHeight = "500px";
            var retValue = openDialogBox(width,hight,callback);
           
            //To preserve the normal JavaScript execution
            if(window. showModalDialog){
                callback(retValue);
          }
 }

function callback(retValue){
    if (retValue != null || retValue != "") {
             alert(retValue);
        }
        else {
             alert('No value returned');
        }
}

We will implement a generic method to open the new window.

function openDialogBox(width,hight,callback){

     if(window. showModalDialog){
          retValue = window.showModalDialog(urlPath, arrArguments, "dialogWidth:" + width +";dialogHeight:" + hight+ ";center:yes;help:no;resizable:no;status:no;scroll:no");
     }
     else{
        windowUnloadEvent(width,height, callback);
    }
}


function windowUnloadEvent(width,height, callback){
    var childWindow = window.open(urlPath,"","toolbar=no, directories=no, location=no, status=yes, menubar=no, resizable=yes, scrollbars=no, width="+Width+", height="+Height);
   
        $(childWindow).unload(function(){
            //We use isOpened propoerty to see whether the "unload" event is being called for the second time.
            //On the first time, isOpened is not defined, so we don't call the callback on that occassion.
            //In the second time, isOpened is defined, so can call the callback function.
            if (childWindow.isOpened == null) {
                childWindow.isOpened = 1;
            }
            else {
                if(callback){
                    callback(childWindow.returnValue);
                }
            }
        });
}

By using above method we can simply replace the showModalDialog with window.open, but sometimes there should be a server side event also trigger after the client side event. To achieve this we need to do the post back by force and to trigger the appropriate server side event we need a sender element. So we need to pass the sender also.

  function openNewWindow(sender) {
            var ModalWidth = "100px";
            var ModalHeight = "500px";
            var retValue = openDialogBox(width,hight,callback,sender);
           
            //To preserve the normal JavaScript execution
            if(window. showModalDialog){
      return  callback(retValue);
            }
 }

function callback(retValue,sender){
    if (retValue != null || retValue != "") {
                 alert(retValue);

// sender null implies normal JavaScript execution
              if(sender == null){
        retuen true;
}
setTimeout(function () { __doPostBack(getElementDynamicName(sender), ''); }, 500); // forcely doing the post back

        }
        else {
             alert('No value returned');
        }
}

function openDialogBox(width,hight,callback,sender){

     if(window. showModalDialog){
    retValue = window.showModalDialog(urlPath, arrArguments, "dialogWidth:" + width +";dialogHeight:" + hight+ ";center:yes;help:no;resizable:no;status:no;scroll:no");
     }
     else{
       windowUnloadEvent(width,height, callback,sender);
    }
}


function windowUnloadEvent(width,height, callback,sender){
    var childWindow = window.open(urlPath,"","toolbar=no, directories=no, location=no, status=yes, menubar=no, resizable=yes, scrollbars=no, width="+Width+", height="+Height);
   
        $(childWindow).unload(function(){
            //We use isOpened propoerty to see whether the "unload" event is being called for the second time.
            //On the first time, isOpened is not defined, so we don't call the callback on that occassion.
            //In the second time, isOpened is defined, so can call the callback function.
            if (childWindow.isOpened == null) {
                childWindow.isOpened = 1;
            }
            else {
                if(callback){
                    callback(childWindow.returnValue,sender);
                }
            }
        });
}
The reason for using the setTimeout function, sometimes the form element is not initialized properly at the time the callback function calls(this step only need in low processing power devices only such as iPads). 

1 comment:

  1. the code doesn`t work. Do you have an working example??

    ReplyDelete