14/04/2014

Custom thank you dialog in a Survey

How to create a custom thank you dialog in a SharePoint 2010 survey


This blog post describes how to create a custom thank you dialog for all your SharePoint 2010 Surveys. The solution is implemented by the use of Visual Studio and SharePoint Designer. I have found many blog posts and questions in forums on this matter, but none of them seems to have a solution that works on a multiple paged survey with validation.

This solution works on a multiple paged survey with OOTB validation!

1) Create custom survey list definition

This is described in step 1 of this blog post: Lillebuen IT blog post: Hide Save and Close button in Survey

2) Create an item event receiver  for the list
  • Right click on the list definition folder in Visual Studio
  • Choose Add > New Item...
  • Choose Even Receiver and give the event receiver a name, e.g. MyEventReceiver
  • In the customization wizard:
    • Choose List Item Event
    • Choose your survey list definition (MySurvey)
    • Check "An item is being added" and "An item is being updated"
  • Add code to display a dialog after the invoking the base methods
The Item event receiver shall look like this:

namespace Namespace.ListDefinitions.MySurvey.MyEventReceiver
{
    public class MyEventReceiver: SPItemEventReceiver
    {
        private readonly HttpContext _currentContext;
        public SurveyListReceiver()
        {
            if (HttpContext.Current != null)
            {
                _currentContext = HttpContext.Current;
            }
        }

        private void DisplayConfirmationMessage()
        {
            if (_currentContext != null)
            {
                _currentContext.Response.Write(
                    "<script type='text/javascript'>alert('We have received your answers. Thank you for your participation.');</script>");
            }
        }

        public override void ItemAdding(SPItemEventProperties properties)
        {
            base.ItemAdding(properties);
            try
            {
                DisplayConfirmationMessage();
            }
            catch (Exception ex)
            {
                // error handling code
            }
        }

        public override void ItemUpdating(SPItemEventProperties properties)
        {
            base.ItemUpdating(properties);
            try
            {
                DisplayConfirmationMessage();
            }
            catch (Exception ex)
            {
                // error handling code
            }
        }
    }
}


I have tried displaying the Thank you text in a SharePoint:UI:Dialog, but I haven't figured out how. It seems like I cannot add script references when doing it like this. Please tell me if anyone have a solution to this.

The reasons for implementing it like this are many:
  • There are many blog posts suggesting that the PreSaveAction javascript method can be invoked, but this method is invoked before the OOTB survey validation. A dialog saying thank for your response, with a survey containing errors is quite stupid.
  • Others suggest setting the Source in the URL. This works perfectly on a survey with one page. But when a survey contains more than one page, the survey generates more than on response per actual End User response and the thank you page never shows...
  • I have also tried doing a redirect in the methods above, but this will cancel the event.
  • I have also tried doing a redirect in the ItemAdded and ItemUpdated methods instead, but this is not possible since these methods are asynchronously, itemAdding and itemUpdating however are synchronously.

SharePoint 2010 Surveys: Hide Save and Close button

How to hide the Save and Close button in  a SharePoint Survey


Why?

When creating a survey with more than on page the "Save and Close" button appears in the Survey dialog. If the End User presses the Save and Close button, the End User can finish the survey response later. This is actually a good functionality in many cases, e.g. very long surveys. My experience shows however that the End User can easily misunderstand the Save and Close, and believe that they are done with the survey response.
The only one that can edit and find such an incomplete survey response is the End User. No admin users can ever find this response. The only way to find out is to check the database (if you suspect that this has happened). How to do this is described in this post: Incomplete responses.

A better way to fix this for all future survey responses is however to hide the "Save and Close" button by creating a customized survey list definition.

How? 


1) Create a new list definition in Visual Studio

  • Create a new farm solution
  • Add > New Item...
  • Choose List and give it a name
  • Set display name and choose "Create a customizable list based on:" and "Default (Blank)"
  • Finish
  • Remove the list instance (you do not need it)
  • Edit Elements.xml (see below)
  • Edit Schema.xml (see below)
The Elements.xml shall contain the following:
 
 <?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="
    <ListTemplate
        Name="MySurvey"
        Type="102"
        BaseType="4"
        OnQuickLaunch="TRUE"
        FolderCreation="FALSE"
        SecurityBits="12"
        Sequence="510"
        DisplayName="MySurvey"
        Description="My List Definition"
        Image="/_layouts/images/itsurvey.png"/>
</Elements>
 

Edit the Schema.xml file:
  • Copy all content from the %14%/template/feature/surveylist/schema.xml into an editor
  • Edit the line that starts with <List xmlns:ows to match your list:
<List xmlns:ows="Microsoft SharePoint" Title="MySurvey" FolderCreation="FALSE" Direction="$Resources:Direction;" Url="Lists/MySurvey" BaseType="4" xmlns="http://schemas.microsoft.com/sharepoint/">
  • Open your schema.xml in Visual Studio and replace all content
Now you can test the custom survey. It shall be exactly the same as the OOTB survey.

2) Create custom NewForm

  • Navigate to your custom or an OOTB survey in the browser.
  • Site Actions > Edit in SharePoint Designer
  • Wait until SharePoint Designer is ready!
  • Navigate to your survey in SharePoint Designer
  • Open the NewForm.aspx file in Advanced Mode
  • Wait until SharePoint Designer is ready!
  • Copy all the code
  • Open an editor and past in the code
  • Go to Visual Studio and create a new application page (Add > New Item > Application Page)
  • Name the file MyNewForm.aspx
  • Move the file (not the parent folders) into your list definition created in step 1 (use drag and drop)
  • Delete the layout folder in Visual Studio
  • Select MyNewForm.aspx in the Solution Explorer and change its property "DeploymentType" to "ElementFile"
  • Open MyNewForm.aspx
  • Delete all content except the first line; also change the MasterPageFile property, result:
<%@ Page language="C#" MasterPageFile="~masterurl/default.master" Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage,Microsoft.SharePoint,Version=14.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" meta:webpartpageexpansion="full" meta:progid="SharePoint.WebPartPage.Document"  %>
  • Copy all the content except the first line (the one displayed above) from the editor
  • Paste into MyNewForm.aspx
  • Remove all content in the ZoneTemplate tag in MyNewForm.aspx
All that is left is to use the MyNewForm.aspx in the custom Survey:
  • Open the schema.xml file
  • Navigate to the bottom of the page.
  • Edit the line that starts with <Form Type="Newform
<Form Type="NewForm" Url="NewForm.aspx" Template="SurveyForm" SetupPath="features\$SharePoint.Feature.DeploymentPath$\MySurvey\MyNewForm.aspx" WebPartZoneID="Main" />

Test that the correct version of NewForm is displayed in the survey by adding a temporary javascript alert or a paragraph with some temporary text.

3) Create custom EditForm

Same as for NewForm, see step 2

4) Remove Save and Close button in NewForm and EditForm

In EditForm.aspx and NewForm.aspx between the SharePoint:UIVersionedContent end tag and asp:Content end tag add this javascript:

<script type="text/javascript">
    var x = document.getElementsByTagName("input");
    for (var i = 0; i < x.length; i++) {
        if (x.item(i).type == "button" && x.item(i).value == "Save and Close") {
            x.item(i).style.display = "none";
        }
    }
</script>


The script iterates through all input controls. If the value of the control is "Save and Close", the display style property is set to "none".

References

09/11/2013

Managed Metadata column disabled in List when creating a new item in the list.

When you try to set a Managed Metadata column for a new list item it looks like this:

 
Fix:
  • List Settings > Click on Managed Metadata column
  • Select Term Set (if selected before do it any way)
  • Click OK
 When you try to set a Managed Metadata column for a new list item now it looks like this:

09/10/2013

Modify your Master Page to display the top level web description

1) Create a new Web Control

The web control shall retrieve the description from your top level site.

In your Visual Studio project, right click and choose Add > New Item... In the New Item dialogue select Module. Give the new module a name (SiteDescription) and click OK.
Remove the txt file.
Add a class (Add > Class...), give it a name (SiteDescription) and click Add.
The source code of your class will look something like this:

namespace NameSpace.SiteDescription
{
    /// <summary>
    /// SiteDescription class is used to displayes the description of the top level web.
    /// </summary>
    [ToolboxData("<{0}:SiteDescription runat=server></{0}:SiteDescription>")]
    public class SiteDescription : WebControl
    {
        private string _alt = "- default description of site";

        /// <summary>
        /// override so that the surrounding tag is a div insteadof a span
        /// </summary>
        protected override HtmlTextWriterTag TagKey
        {
            get { return HtmlTextWriterTag.Div; }
        }

        /// <summary>
        /// Add the description as an em tag
        /// </summary>
        /// <param name="writer"></param>
        [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust"
            )]
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Em);
            writer.WriteEncodedText(_alt);
            writer.RenderEndTag();
        }

        private void InitiateDescription()
        {
            try
            {
                var webApp = SPContext.Current.Site.WebApplication;
                SPWeb siteToUse = SPContext.Current.Web;
                foreach (SPSite site in webApp.Sites)
                {
                    if (site.RootWeb.Title.Equals("Title")) /* your title...*/
                    {
                        siteToUse = site.RootWeb;
                        break;
                    }
                }
                if (!String.IsNullOrEmpty(siteToUse.Description))
                {
                    _alt = siteToUse.Description;
                }
              
            }
            catch (Exception e)
            {
                /*error handling*/
            }
        }

        /// <summary>
        /// Create new web control
        /// </summary>
        public BannerDescription()
        {
            InitiateDescription();
        }
    }
}


Edit the Elements.xml file of your new Web Control:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control
   Id="SiteDescription"
   Sequence="24"
   ControlClass="Namespace.SiteDescription.SiteDescription"
    ControlAssembly="Namespace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxx">
  </Control>
</Elements>


2) Use your description web control in your master page

<NameSpace:SiteDescription ID="SiteDescriptionWebControl" runat="server"/>

Visual Studio will prompt you with the right import statements.