Resizing your add-in showing in a modal dialog

SharePoint has an option to resize the app-part or add-in iframe from within the add-in. See for example 4 Steps to smarter App Part resizing. This only works for a ClientWebPart (app-part), and does not work when you are using a HostWebDialog. So if you specify a ribbon custom action, or an edit control block custom action in your add-in, using HostWebDialog then the postMessage option will not work.

Custom Action:

  <CustomAction Id="0ad636fa-afee-46a6-99c0-cc548e93a165.RibbonCustomActionSample"
                RegistrationType="List"
                RegistrationId="101"
                Location="CommandUI.Ribbon"
                Sequence="10001"
                Title="Sample resize popup"
                HostWebDialog="true"
                HostWebDialogHeight="180"
                HostWebDialogWidth="280">
    

JavaScript:

  var message = "<Message senderId=" + senderId + ">"
  + "resize(" + width + "," + height + ")</Message>";
  window.parent.postMessage(message, "*");
    

So that is a bummer. I also looked at the autoResize option available for the SharePoint dialog, see SharePoint 2010: Easy Dynamic Resize of Dialogs. As stated there, the code (SP.UI.ModalDialog.get_childDialog) is called from within the popup content, and this code is only available from within the SharePoint site itself, and is not an option when using an add-in.

Now I went and put these things together to enable the resizing of the add-in dialog from withing the add-in. For this you need to handle the (on)message event from within the SharePoint site. And for convenience I have enabled the usage of the same message format as used for a ClientWebPart, so you can use the same add-in code for resizing the ClientWebPart and the HostWebDialog.

For development and test purposes I have created a SharePoint hosted add-in with the above mentioned user custom action, that is available from within the document library. Then I created a Sandboxed Solution that will add a ScriptLink to the site with a reference to the resize script. You can download the add-in and sandbox solution as ResizePopupSample.zip. Install the app in your dev site, or dev app catalog and then install it in a dev site. And install the sandbox solution to enable resizing from within your add-ins. You could also add a scriptlink on the AppInstalled event of a provider hosted app, but this will not fire when using app stapling. You cannot add a scriptlink from within a SharePoint hosted app (or so I thought, see Update 5/13/2016).

Screenshot of app dialog

If you then go to a document library, and select a document, you can see the Sample option of the add-in in the documents tab in the Manage section. If you click this, the dialog will show and you will have two options to test resizing. One by setting the size yourself, and one automated test that enlarges the dialog end then shrinks the dialog back again.

So the main part is lots of boring sizing javascript code in the ResizeDialog function. And some code to handle the message event:

window.receiveDialogResizeMessage = window.receiveDialogResizeMessage || function (event) {
    if (event.data != null && event.data.toLowerCase().indexOf('<message ') == 0) {
        try {
            var parser = new DOMParser();
            var message = parser.parseFromString(event.data, "text/html").getElementsByTagName("message")[0];
            if (message.attributes["senderid"].value != '') // check sender
                return; // popups don't have a senderId so this is from a add-in part.
            var size = message.textContent.replace("resize(", "").replace(")", "").split(',');
            if (size != null && size.length == 2) {
                window.ResizeDialog(size[0], size[1]);
            }
        }
        catch (e) {
            if (window.console)
                console.log('Error parsing received message: ' + e);
        }
    }
};
window.attachedResizeDialog = window.attachedResizeDialog || false;
if (!window.attachedResizeDialog) {
    if (window.addEventListener) {
        addEventListener('message', receiveDialogResizeMessage, false);
        window.attachedResizeDialog = true;
    } else {
        attachEvent('onmessage', receiveDialogResizeMessage);
        window.attachedResizeDialog = true;
    }
}
    

I have used the DOMParser and some replace statements here, but you probably could use a regular expression instead. For the full script see: ResizeDialog.js

I have tested this with minimal download strategy on and off, and with recent versions of Firefox, Internet Explorer and Chrome. Still as I always state, test this yourself before using this.

Update 4/17/2016

Have updated the ResizePopupSample.zip, as I found out the sandbox solution 'EnableResizeDialog.wsp' did not function properly. I now fixed this issue, and also set the project property 'Include Assembly In Package' to False, as this is a no code sandbox solution, and no assembly is needed. If you downloaded this file earlier, you can now download the updated file.

Update 5/13/2016

Well as I wasn't a 100% sure I was correct when mentioning that you can't add a ScriptLink from a SharePoint hosted add-in, so I went and tested this and I found out that it was possible after all. I have now added a sample that describes how this can be done Add a ScriptLink on the host web from a SharePoint hosted app with JSOM

Update 6/1/2016

I thought it worked with minimal download strategy (MDS) on, but I noticed it didn't. So I have updated the sandboxed solution in the .zip file and the ResizeDialog.js file. If you already downloaded and installed the sandbox solution, please update the javascript file in the Style Library, and make sure that the file gets refreshed to avoid caching issues.

I should have known, that this would be an issue, as anonymous javascript functions don't work well with MDS. Code added:

function InitResizeDialogAfterMinimalDownload() {
    if (window.asyncDeltaManager && window.asyncDeltaManager.add_endRequest) {
        asyncDeltaManager.add_endRequest(function () {
            InitResizeDialog();
        });
    }
}

if(window._spBodyOnLoadFunctions) {
    _spBodyOnLoadFunctions.push(InitResizeDialogAfterMinimalDownload);
    _spBodyOnLoadFunctions.push(InitResizeDialog);
}
    

That fixed the issue with MDS.

Update 6/3/2016

I have noticed an issue with office web apps and javascripts added with a scriptlink. When debugging script for a Word Add-In I noticed error messages ReferenceError: _spBodyOnLoadFunctions is not defined. I also found that also my own scripts gave out these errors. Now I have updated everything (also script above) with a check if _spBodyOnLoadFunctions is available, before adding functions to this array. If you already installed the solution, please update the javascript file in the Style Library.