Data validation in publishing pages in SharePoint 2010

Like many things in SharePoint – this should be simple but turns out it is not. I had a requirement to ensure that a DateTime field (Next Review Date) on the page is equal to or greater than the current date. This field is part of a content type and is included on the page layout for editing.

My first attempt was to add a column validation formula for the Next Review Date column. This worked well when the properties of the page was being edited through the list (i.e. edited as a list item). However, this did not work when the page was being edited as a publishing page (i.e. content editing). If the user saves the page with a bad value in the field, he/she would simply get a Save Conflict dialog and the validation error message is not displayed anywhere. There is no way for the user to work out what’s going on.

My second attempt was to add an ASP.NET validator control (e.g. CompareValidator) to the page layout. The problem here is that all ASP.NET validators (except for the CustomValidator) can only validate certain types of controls, and the SharePoint DateTimeField is not one of them. Try referencing the SharePoint field in the validator and you will get the error below in the ULS:

System.Web.HttpException: Control ‘DateTimeField’ referenced by the ControlToValidate property of ‘validator’ cannot be validated.

My final approach was to tweak the Template of the field on the page layout and using a custom control that inherits from the OOTB one. This is described below. While custom code was required in this instance, this could lead to no code solutions in other scenarios.

Normally the markup of the field on the page layout looks like below:

<SharePointWebControls:DateTimeField FieldName="NextReviewDate" runat="server" />

SharePoint uses Rendering Template to render the markup above. If you open up the file C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\CONTROLTEMPLATES\DefaultTemplates.ascx and search for “DateTimeField” you will find the markup below:

<SharePoint:RenderingTemplate id="DateTimeField" runat="server">
	<Template>
		<SharePoint:DateTimeControl id="DateTimeField" runat="server"/>
	</Template>
</SharePoint:RenderingTemplate>

This means SharePoint will render the DateTimeField using the DateTimeControl.

We can actually override this in our page layout. First, update the markup in the page layout to be:

<SharePointWebControls:DateTimeField FieldName="NextReviewDate" runat="server">
	<Template>
		<SharePoint:DateTimeControl id="DateTimeField" runat="server"/>
	</Template>
</SharePointWebControls:DateTimeField>

Deploy and test to make sure everything still works. Now, I tried adding a Validator control to the Template and reference the DateTimeControl, but this is also not a control that can be validated (doh!).

Luckily, the OOTB DateTimeControl has a MinDate and MaxDate properties, which work quite nicely. So update the markup in the page layout to below and deploy and test:

<SharePointWebControls:DateTimeField FieldName="NextReviewDate" runat="server">
	<Template>
		<SharePoint:DateTimeControl id="DateTimeField" MinDate="30/08/2011" runat="server"/>
	</Template>
</SharePointWebControls:DateTimeField>

This should work very nicely, but obviously the MinDate needs to be today’s date and cannot be hardcoded. You could set the MinDate using the syntax below:

MinDate="<%# DateTime.Today.ToShortDateString(); %>"

However, SharePoint by default will prevent this, and you will get the error message: Code blocks are not allowed in this file. You could modify the web.config to enable code blocks in the page and be done with it, but I wasn’t keen on this.

To workaround this, I created a simple custom DateTimeControl class that inherits from the OOTB one. This class will have 2 custom properties: RestrictToTodayOrGreater and RestrictToTodayOrLess, which when set to true will set the MinDate and MaxDate to today’s date. Below is the complete code:

public class MyDateTimeControl : DateTimeControl
	{
		protected override void OnInit(EventArgs e)
		{
			if (this.RestrictToTodayOrGreater)
			{
				base.MinDate = DateTime.Today;
			}
			if (this.RestrictToTodayOrLess)
			{
				base.MaxDate = DateTime.Today;
			}
			base.OnInit(e);
		}

		///
<summary> /// Sets or gets whether the MinDate will be set to today's date.
 /// </summary>
		public bool RestrictToTodayOrGreater
		{
			get;
			set;
		}

		///
<summary> /// Sets or gets whether the MaxDate will be set to today's date.
 /// </summary>
		public bool RestrictToTodayOrLess
		{
			get;
			set;
		}
	}

Now update the markup on the page layout to use our custom DateTimeControl:

<SharePointWebControls:DateTimeField FieldName="NextReviewDate" runat="server">
							<Template>
								<MyControls:MyDateTimeControl id="DateTimeField" RestrictToTodayOrGreater="true" runat="server"/>
							</Template>
						</SharePointWebControls:DateTimeField>

We will also need to register our control at the top of the page layout:

<%@ Register tagprefix="MyControls" namespace="MyControls" assembly="[strong name goes here]" %>

Finally, we need to add our custom control to the Safe Controls list. Use the Package Explorer in Visual Studio to do this.

That’s it. Go ahead and deploy your solution.

Advertisements

About Bernado

Based in Australia, I am a freelance SharePoint and Dynamics CRM developer. I love developing innovative solutions that address business and everyday problems. Feel free to contact me if you think I can help you with your SharePoint or CRM implementation.
This entry was posted in Page Layout, SharePoint 2010. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s