December 09, 2011

SharePoint 2010 Modal Dialogs and JavaScript

SharePoint 2010 came with a whole lot of new features.  One of them is to dispaly list pages through a Modal Dialog.  These modal dialogs can be enabled or disabled in the list settings.
In this blog I show the use of SP.UI.ModalDialog and related objects to create a feedback form.  The code consists of a single HTML link element and some JavaScript to display the modal dialog, and the confirmation dialog. 
SharePoint 2010 also came with a new item on the master page called status bar.  The status bar is somewhat similar to a status bar on any browser window.  In the OOTB (Out Of The Box or unmodified) master page this status bar appears right under the navigation bar.  Though it is not visible all the time, it is used to update the user with the status of the activity he is undertaking.  I also show the use of status bar in this code.
This whole code I am about to show can be put in a text file, uploaded to the site (Style Library or any other document library) and used as the source for a Content Editor Web Part.

Here we go, first I put down the HTML for the link with an onclick event:
<a onclick="javascript:portal_ShowFeedbackDialog();" href="#">I want to give feedback</a>

The following function is called for the onclick event.  The code is straight forward.  The variable L_Menu_BaseUrl is created by SharePoint code.  You can view the source of a SharePoint page to see this variable.  Don't forget to wrap your JavaScript in the <script type="text/javascript"></script> tags.

function portal_ShowFeedbackDialog() {
    var options = SP.UI.$create_DialogOptions();
    options.width = 600;
    options.height = 400; 
    options.url = L_Menu_BaseUrl + "/Lists/Feedback/NewForm.aspx";
    options.dialogReturnValueCallback = Function.createDelegate(
                        null, portal_modalDialogClosedCallback);
    SP.UI.ModalDialog.showModalDialog(options);
}


This code shows the modal dialog box as shown in the following picture



When the user saves the item after providing the feedback and title fields, the portal_modalDialogClosedCallback code is triggered.

function portal_modalDialogClosedCallback(result, value) {
    if (result == '1') {
  showNotificationDialog("<div><h1>Feedback Submitted</h1></div><div>Thank You!  Your feedback has been submitted to the site owner.</div>");
        this.statusId = SP.UI.Status.addStatus("Feedback Submitted", "Thank You!  Your feedback has been submitted to the site owner.", true);
        SP.UI.Status.setStatusPriColor(this.statusId, "Green");
    }
    else if (result == '0') {
  showNotificationDialog("<div><h1>Feedback Submission Failed</h1></div><div>Your feedback could <b>not</b> be submitted. Please try again.</div>");  
        this.statusId = SP.UI.Status.addStatus("Feedback Submission Failed", "Your feedback could <b>not</b> be submitted. Please try again.", true);
        SP.UI.Status.setStatusPriColor(this.statusId, "Green");
    }
 else{this.statusId = SP.UI.Status.addStatus("Feedback Unknown", "The status of your feedback is unknown", true);}
    setTimeout(RemoveStatus, 6000);
}


  This code does two things.  First it shows another dialog box listing the status of submitted item as shown in the following picture.

 
Second it adds a status in the status bar in the main page where the action was triggered from.  Again the adding of the status relies upon the addStatus method of SP.UI.Status object provided by SharePoint.  Once the status is added, it must be removed after sufficient time has been provided to the user to view it.  This is done via the following line of code which uses JavaScript setTimeout() method to invoke the removeStatus metod of the Status object via a helper function.

setTimeout(RemoveStatus, 6000); 

 Based on your requirements, you may or may not need to implement both methods to communicate the status of the feedback. 

The rest of the code contains the creation of confirmation dialog box.  The html to show on the dialog box is created via the JavaScript and passed to the dialog box using the options object.


function RemoveStatus() {
    SP.UI.Status.removeStatus(this.statusId);
}
 function showNotificationDialog(messageToShow) {
    var options = SP.UI.$create_DialogOptions();
    options.title = "Feedback Confirmation";
    options.allowMaximize = false;
    options.width = 300;
    options.height = 150;   
    options.showClose = true;
    var _html = document.createElement('div');
    var btnClose = '<div align="center" style="margin-top:15px;"><input type="button" value="OK" name"OK" onclick="javascript:SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel);" /></div>';
 _html.innerHTML = messageToShow + btnClose;
 options.html = _html;
 SP.UI.ModalDialog.showModalDialog(options);
}
This is just a very simple example of how SharePoint's dialog JavaScript API can be used to create custom dialog boxes.

November 25, 2011

InfoPath: How to host new and edit form on a web part page

One of the main issues with hosting web enabled InfoPath forms is that of the branding.  The form shows up as full screen page without the master page.  Hence there is no navigation available for the end user to go to other parts of the site.  In this writing I share a complete solution for InfoPath forms to display them inside a master page. 
Here is how a form looks like without a master page.
InfoPath form displayed in SharePoint site without master page

Notice that SharePoint renders the form using an application page with a URL /_layouts/FormServer.aspx.  This page is actually specified in a configuration xml file under the 12 or 14 hive (depending on your version of SharePoint) at \12\TEMPLATE\XML\serverfiles_FormServer.xml.  The contents of the file look like the following:


<?xml version="1.0" encoding="utf-8"?>
<ServerFiles>
                <Mapping FileExtension="xml" ProgId="InfoPath.Document" RedirectUrlTemplate="/_layouts/FormServer.aspx?XmlLocation=|0" />
                <Mapping FileExtension="xml" ProgId="InfoPath.Document.2" RedirectUrlTemplate="/_layouts/FormServer.aspx?XmlLocation=|0" />
                <Mapping FileExtension="xml" ProgId="InfoPath.Document.3" RedirectUrlTemplate="/_layouts/FormServer.aspx?XmlLocation=|0" />
                <Mapping FileExtension="xml" ProgId="InfoPath.Document.4" RedirectUrlTemplate="/_layouts/FormServer.aspx?XmlLocation=|0" />
                <Mapping FileExtension="xsn" RedirectUrlTemplate="/_layouts/FormServer.aspx?XsnLocation=|0" />
</ServerFiles>


We can easily change this file to set the RedirectUrlTemplate to a custom page within our site but it is not the recommended way.  Any service updates will overwrite the file and functionality will be lost.  The trick here is to create another file with a name which is similar to the existing name but comes after the original file name when alphabetically sorted in ascending orde.
One such name would be serverfiles_FormServerCustom.xml
The SharePoint platform seems to register these files in alphabetical order.  So by placing a different mapping in our custom file, it is possible to overwrite the settings without breaking SharePoint.  Here is what the file content of out custom file will look like.


<?xml version="1.0" encoding="utf-8"?>
<ServerFiles>
  <Mapping FileExtension="xml" ProgId="InfoPath.Document" RedirectUrlTemplate="/Pages/EditForm.aspx?XmlLocation=|0" />
  <Mapping FileExtension="xml" ProgId="InfoPath.Document.2" RedirectUrlTemplate="/Pages/EditForm.aspx?XmlLocation=|0" />
  <Mapping FileExtension="xml" ProgId="InfoPath.Document.3" RedirectUrlTemplate="/Pages/EditForm.aspx?XmlLocation=|0" />
  <Mapping FileExtension="xml" ProgId="InfoPath.Document.4" RedirectUrlTemplate="/Pages/EditForm.aspx?XmlLocation=|0" />
  <Mapping FileExtension="xsn" RedirectUrlTemplate="/Pages/NewForm.aspx?XsnLocation=|0" />
</ServerFiles>


It would be very obvious now that I plan to create two pages in the Pages library, which are NewForm.aspx and EditForm.aspx.    Both of them would be web part pages.  In my case I like to user the “Blank Web Part Page”.   On the NewForm page add a Page Viewer Web Part.  In the Page Viewer Web Part’s properties, set the property called “Link” as follows:

/_layouts/FormServer.aspx?OpenIn=browser&XsnLocation=/FormServerTemplates/MyInfoPathForm.xsn

Make sure the XsnLocation is the location where you have published the form.  You may also want to adjust the height or the width.   Once you save and publish the NewForm.aspx page, it would display your InfoPath form.  And yes, it would have your master page.


The EditForm page requires a bit of coding.  Basically the idea is the same as the NewForm to host a web part which will accept XmlLocation parameter and display the contents from this URL.  In this case the URL (XmlLocation) is going to be dynamic because the form is already saved and all saved forms will have different URLs.  So we need a dynamic way to set the “Link” property of the Page Viewer Web Part.  The quick and easy way is to wrap the PageViewerWebPart class in a custom web part.  I present the minimal code for your interest.  The main code is in the CreateChildControls method.


private PageViewerWebPart pageViewer;
[Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("Custom Properties")]
        [WebDisplayName("Form Page Url")]
        [WebDescription("Url of edit form page")]
        public string PageUrl
        {
            get
            {
                if (_pageUrl == null)
                {
                    _pageUrl = "/_layouts/FormServer.aspx";
                }
                return _pageUrl;
            }
            set { _pageUrl = value; }
        }
        protected override void CreateChildControls()
        {
            if (!_error)
            {
                try
                {
                    base.CreateChildControls();
                    // Your code here...
                    String contentLink = PageUrl + "?";
                    String queryData = Context.Request.Url.ToString().Split(new char[] {'?'}, StringSplitOptions.RemoveEmptyEntries)[1];
                    pageViewer = new PageViewerWebPart();
                    pageViewer.ContentLink = contentLink + queryData;
                    pageViewer.ChromeType = this.ChromeType;
                    pageViewer.ChromeState = this.ChromeState;
                    pageViewer.Width = this.Width;
                    pageViewer.Height = this.Height;
                    pageViewer.Hidden = this.Hidden;
                    pageViewer.Title = this.Title;
                    this.Controls.Add(this.pageViewer);
                }
                catch (Exception ex)
                {
                    HandleException(ex);
                }
            }
        }


Once webpart is deployed to the SharePoint server, add it to the Editform page.  Set all the properties of this web part as you had set the properties on the Page Viewer Web Part.  Once you save the page and publish it, the web part would be able to open the InfoPath forms in edit mode.


Make sure you deploy the serverfiles_FormServerCustom.xml to the \12\Template\XML folder.


InfoPath forms (edit and new) displayed within master page.

Now if you go to any of the saved forms, and click on the link, they will open up in a page with master page.

Jagjit Assi

I am a SharePoint Developer and Solution Architect working in Toronto, Ontario.  My formal education is in engineering field and specifically in computers.  I have been working on SharePoint technology from past five years.  I hope to use this site for communicating my experiences and learning of this technology with the rest of the community.