Situation
If you’ve worked with SharePoint 2010 at all, I’m sure you’ve seen a ModalDialog popup at some point. This popup most often occurs when you’re creating or editing a list item. The item’s edit or create form is displayed by ModalDialog in an HTML iFrame. This frame allows for the nifty, AJAX-like popup, but it also means that the form code is segregated from the rest of the page. This isn’t really a problem with out-of-the-box forms, which use the Dialog master page. The dialog master page provides Save and Cancel buttons in the ribbon, among others. But what if you don’t want to or can’t use the Dialog master page?
If you’re using the default master page, whatever that may be, it typically does not provide Save/OK and Cancel buttons for a dialog. It does, however, clear away most navigation elements and just displays the ContentPlaceHolderID named PlaceHolderMain when IsDlg=1 is in the query string. What this means for you is your buttons need to be in PlaceHolderMain or they might not be rendered. Anyway, regardless of which master page your page actually uses, it can’t communicate with the underlying page that opened it as a dialog.
To facilitate the communication, you’ll need SP.UI.ModalDialog. This is provided as part of the SharePoint JavaScript Object Model and is how SharePoint opens a ModalDialog (via the showModalDialog function). I’m going to skip over opening a ModalDialog because that’s relatively easy, with examples all over the web. What is hard to find are examples for closing a ModalDialog. While it’s true that you’re just calling commonModalDialogClose, how do you call it and, more importantly, where do you call it.
Once your page POSTs back correctly and whatever you needed to do is done, if you don’t close the ModalDialog that your page is in, the user can’t return to work automatically. This breaks the flow of the application and can be rather frustrating for the user. After all, it’s easy for the user to close the ModalDialog, why wasn’t it easy for the developer?
Solution
Fortunately, it is incredibly easy for the developer to close a ModalDialog in SharePoint, once you know where to close it. The correct place is after the page has posted back via a registered startup script. This startup script will simply call commonModalDialogClose with the correct parameters. These parameters are important because SharePoint uses them to determine which callbacks to execute when the dialog is closed. CommonModalDialogClose takes two arguments: dialogResult and returnVal. The first indicates whether the ModalDialog either succeeded or failed and the second is a value passed into the callback methods.
I won’t go into detail with what you can do with callback methods, but the simplest action is to display the result in the SharePoint status bar. The status bar appears right below the ribbon when there is a message in it and can be either red, green, or yellow in color. This is the subject of a future blog post.
Where I prefer to put my code for closing the page is inside the callbacks for the buttons I have on the page. Every page usually has an OK and (usually) a Cancel button. These are the prefect place to place RegisterStartupScript calls. Before we get there, however, my page looks like the following (with all of the Assembly references removed):
1: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AddDeleteWorkflow.aspx.cs"
2: Inherits="PB.SharePoint.Layouts.PB.SharePoint.AddDeleteWorkflow"
3: DynamicMasterPageFile="~masterurl/default.master" %>
4:
5: <asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
6: </asp:Content>
7: <asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
8: <asp:Button runat="server" Text="Ok" ID="ButtonOk" OnClick="ButtonOk_Click" />
9: <asp:Button runat="server" Text="Cancel" ID="ButtonCancel" OnClick="ButtonCancel_Click" />
10: </asp:Content>
11: <asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
12: Title
13: </asp:Content>
14: <asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea"
15: runat="server">
16: Title
17: </asp:Content>
The important functions here are ButtonOk_Click and ButtonCancel_Click. These check that the IsDlg parameter is set and then register a startup script to close the dialog. Importantly, although the first parameter of commonModalDialogClose is of SP.UI.DialogResult type, this type may not be loaded by the time your startup script executes. To get around that, use the integer values for the enumeration names instead (0, 1, and –1).
1: protected void ButtonOk_Click(object sender, EventArgs e)
2: {
3: string isDlg = this.Request.QueryString.GetValues("IsDlg");
4: if (!String.IsNullOrEmpty(isDlg) && isDlg == "1")
5: {
6: this.Page.ClientScript.RegisterStartupScript(this.GetType(), "PopupScript", "SP.UI.ModalDialog.commonModalDialogClose(1, 1);", true);
7: }
8: }
9:
10: protected void ButtonCancel_Click(object sender, EventArgs e)
11: {
12: string isDlg = this.Request.QueryString.GetValues("IsDlg");
13: if (!String.IsNullOrEmpty(isDlg) && isDlg == "1")
14: {
15: this.Page.ClientScript.RegisterStartupScript(this.GetType(), "PopupScript", "SP.UI.ModalDialog.commonModalDialogClose(0, 0);", true);
16: }
17: }
Now that you know how to close a ModalDialog, you should be able to make your page much more AJAX-y! Cheers!
Thank you very much.
It is very helpful.
Thank you!!! I implemented a custom upload page but couldn’t get the page to refresh after the file was uploaded.