4/20/2015

Close Modal Dialog from App page in Provider-Hosted App

Sometimes there is a necessity to show some App page in Modal Dialog.
For example, show some settings on custom action click.
It is simple to show the dialog, but standard approach of closing it doesn't work because the App and SharePoint site can be hosted on different domains. And we can't just commit popup from cross-domain frame document.
To close the dialog you can use HTML5 postMessage API.

If we speak about some custom action, and, to be correct, about custom action that was created declaratively with HostWebDialog property set to true, you can use messages CloseCustomActionDialogRefresh to close the dialog and refresh the page or CloseCustomActionDialogNoRefresh to close but without refresh:
var target = parent.postMessage ? parent : 
    (parent.document.postMessage ? parent.document : undefined); 
if (target) 
    target.postMessage((doRefresh ? 'CloseCustomActionDialogRefresh' : 'CloseCustomActionDialogNoRefresh'), '*');
Server-side:
private void CloseDialog()
{
    this.Context.Response.Write(
        "");
    this.Context.Response.Flush();
    this.Context.Response.End();
}
If you open the dialog by custom code (code-created custom action has no HostWebDialog property so it is kind of a dialog opened by custom code) SharePoint doesn't listen to the messages described above. But you can use CloseDialog message and dialogReturnValueCallback to refresh the page:
// open dialog with callback handler example:
SP.UI.ModalDialog.showModalDialog({ 
    url: 'your_app_page_url_or_some_proxy_page_url', 
    // ...
    dialogReturnValueCallback: function CallDETCustomDialog(dialogResult, returnValue) { SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK); } });

// posting a message
var target = parent.postMessage ? parent : 
    (parent.document.postMessage ? parent.document : undefined); 
if (target) 
    target.postMessage('CloseDialog', '*');
Server-side:
private void CloseDialog()
{
    this.Context.Response.Write(
        "");
    this.Context.Response.Flush();
    this.Context.Response.End();
}

That's all, have fun!

3 comments:

  1. This is not working if I open Popup from Popup.

    ReplyDelete
    Replies
    1. Hi Manjeet,
      What exactly doesn't work?

      Delete
    2. For me, I have set 'Open dialog' property to YES for one of the List(Task List). And I have custom action in the ribbon for View form for that Task List. So when I open 'View Item' it opens in popup. And when I click on my custom action it again opens new Popup which is nothing but provider hosted app's page.
      I am calling "target.postMessage('CloseDialog', '*')" function when i clicked on 'Cancel' button from my page. It closing Task List's View Item form but not the page opened recently. The expected behavior is to close the recent page whatever opened recently just like stack operates(Last opened First Closed)

      Delete