OfficeJS: Second Dialog Does not Display


I have been spending a lot of time in the Officeui.dialog lately. One of my customers has been too and it has been an adventure working out exactly the best way to get messages displayed while running code in the background asynchronously. wlEmoticon-disappointedsmile.png

I am not sure if this problem is limited to the online version of Outlook, but this is where I have been seeing the problem (and where I have spent virtually all of my time). If my code tried to open two dialogs (using Office.context.ui.displayDialogAsync()) one right after the other, the second dialog would not ever be displayed. If I waited a period and then tried again, it would. But we don’t want that. We want boom-boom, dialogs. When I looked at the console, I would see an error like the following:

Uncaught TypeError: Cannot read property ‘addEventHandler’ of undefined

Or, if I read the error object from the displayDialogAsync() function/asyncResult, I would see this:

{name: “Display Dialog Error”, message: “The operation failed because this add-in already has an active dialog.“, code: 12007}

Here is an example of some code that will reproduce the issue:

var i = 0;
function displayDialog() {
  var url = "https://localhost:3000/test.html";
  Office.context.ui.displayDialogAsync(url,{height:20, width:30, displayInIframe:true},
      function (asyncResult) {
          var dialog = asyncResult.value; // get the dialog
          var error = asyncResult.error;
          if(dialog == undefined && error.code > 0) {
            // log the error
            console.log(error.message);
          } else {
            // attache the events
            dialog.addEventHandler(Office.EventType.DialogEventReceived, function (arg) {
              // close this dialog, open the next
              dialog.close();
              i++;
              if(i<4) {
                displayDialog();
              }
            });
            dialog.addEventHandler(Office.EventType.DialogMessageReceived, function (arg) {
              // close this dialog, open the next
              dialog.close();
              i++;
              if(i<4) {
                displayDialog();
              }
            });
          }
      });
}

Notice I had used dialog.close(), but it did not work as designed. What I believe is happening is that the previous dialog is still in memory and has not been cleaned up. What needs to likely happen is a closeAsync().

In order to resolve this, I created the following function: dialogCloseAsync(). This works by issuing the close() and then attempting to add an event handler to the dialog in ansyc (setTimeout) loop. When it errors, we trap the error and issue the async callback. It is a bit ugly as we are trapping an error to get around the problem, but this was the only way I could find a way around the problem. Here is what the function looks like:

/**
 * Closes the currently open dialog asynchronously.
 * This has an ugly workaround which is to try to set a new
 * event handler on the dialog until it fails. When it failed
 * we know the original dialog object was destroyed and we
 * can then proceed. The issue we are working around is that
 * if you call two dialogs back to back, the second one will
 * likely not open at all.
 * @param {Office.context.ui.dialog} dialog The dialog to be closed
 * @param {function()} asyncResult The callback when close is complete
 */
 function dialogCloseAsync(dialog, asyncResult){
    // issue the close
    dialog.close();
    // and then try to add a handler
    // when that fails it is closed
    setTimeout(function() {
        try{
            dialog.addEventHandler(Office.EventType.DialogMessageReceived, function() {});
            dialogCloseAsync(dialog, asyncResult);
        } catch(e) {
            asyncResult(); // done - closed
        }
    }, 0);
}

I had been encountering this issue with different systems when developing the OfficeJS.dialogs library and had tried to set a timeout before I showed each dialog. That worked on some systems, but on others the timeout needed to be longer. So, setting a default timeout did not work. Using this in the original sample, provided above, the code would look like this:

var i = 0;
function displayDialog() {
  var url = "https://localhost:3000/test.html";
  Office.context.ui.displayDialogAsync(url,{height:20, width:30, displayInIframe:true},
      function (asyncResult) {
          var dialog = asyncResult.value; // get the dialog
          var error = asyncResult.error;
          if(dialog == undefined && error.code > 0) {
            // log the error
            console.log(error.message);
          } else {
            // attache the events
            dialog.addEventHandler(Office.EventType.DialogEventReceived, function (arg) {
              // close this dialog, open the next
              dialogCloseAsync(dialog, function() {
                i++;
                if(i<4) {
                  displayDialog();
                }
              });
            });
            dialog.addEventHandler(Office.EventType.DialogMessageReceived, function (arg) {
              // close this dialog, open the next
              dialogCloseAsync(dialog, function() {
                i++;
                if(i<4) {
                  displayDialog();
                }
              });
            });
          }
      });
}

As I found this workaround, I have updated OfficeJS.dialogs to use dialogCloseAsync(). Now, the MessageBox, Wait and Form objects will use closeDialogAsync() commands to replace the original closeDialog() commands I provided previously. I will be blogging about the updates to v1.0.6, shortly. wlEmoticon-hotsmile.png

One thought on “OfficeJS: Second Dialog Does not Display

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s