Customizing SharePoint List Forms with Content Type Rendering Templates .


Recently I developed a solution for a client, which centred around a list which managed gift registration data. The client wanted some expressive labels next to the field controls, to provide guidance on how to fill-in each field;

Field Descriptions

Field Descriptions

I showed the client how field descriptions would appear underneath the field controls, but what they wanted was for the field descriptions to appear where the field labels were displayed, instead of the field labels themselves.

A custom list form would certainly do the job, but customisations to a list form don’t travel beyond that specific list (unless you’re using a custom list definition), if the content type being used is added to another list, those customizations would not appear in other lists.

So the solution was to develop a custom rendering template for the content type – a rendering template is quite simply an .ASCX file dropped into the CONTROLTEMPLATES folder in the SharePoint root (14 hive).

Briefly, display or edit fields are rendered using the CompositeField template which is ‘called’ via the ‘ListFieldIterator‘ template;

<SharePoint:RenderingTemplate id="CompositeField" runat="server">
	<Template>
		<td nowrap="true" valign="top" width="190px" class="ms-formlabel"><h3 class="ms-standardheader"><SharePoint:FieldLabel runat="server"/></h3></td>
		<td valign="top" class="ms-formbody">
		<!-- FieldName="<SharePoint:FieldProperty PropertyName="Title" runat="server"/>"
			 FieldInternalName="<SharePoint:FieldProperty PropertyName="InternalName" runat="server"/>"
			 FieldType="SPField<SharePoint:FieldProperty PropertyName="Type" runat="server"/>"
		  -->
			<SharePoint:FormField runat="server"/>
			<SharePoint:FieldDescription runat="server"/>
			<SharePoint:AppendOnlyHistory runat="server"/>
		</td>
	</Template>
</SharePoint:RenderingTemplate>

<SharePoint:RenderingTemplate id="ListFieldIterator" runat="server">
	<Template>
		<tr><SharePoint:CompositeField runat="server"/></tr>
	</Template>
</SharePoint:RenderingTemplate>

As you can see the CompositeField template emits the field label, field control and field description in 2 table cells.

In order for me to emit the field descriptions in place of the field labels, I’m going to need;

  1. A new CompositeField template to display the field description and field control
  2. A new ListFieldIterator template to ‘call’ the new CompositeField template
  3. A new template specifically for the content type, which ‘calls’ the new ListFieldIterator

So lets starts with the new VerboseCompositeField rendering template;

<SharePoint:RenderingTemplate id="VerboseCompositeField" runat="server">
	<Template>
		<td valign="top" width="260px" class="ms-formlabel">
			<h3 class="ms-standardheader">
				<SharePoint:FieldProperty ID="FieldProperty1" PropertyName="Description" runat="server"/>
				<SPAN title='This is a required field.' class="required_<SharePoint:FieldProperty PropertyName='Required' runat='server' /> ms-formvalidation"> *</SPAN>
			</h3>
		</td>
		<td valign="top" class="ms-formbody">
		<!-- FieldName="<SharePoint:FieldProperty PropertyName="Title" runat="server"/>"
			 FieldInternalName="<SharePoint:FieldProperty PropertyName="InternalName" runat="server"/>"
			 FieldType="SPField<SharePoint:FieldProperty PropertyName="Type" runat="server"/>"
		  -->
			<SharePoint:FormField ID="FormField1" runat="server"/>
			<SharePoint:AppendOnlyHistory ID="AppendOnlyHistory1" runat="server"/>
		</td>
	</Template>
</SharePoint:RenderingTemplate>

So this emits the field description and field control, next to the field description it also emits a SPAN containing the required field * character, the SPAN’s class is set to “required_” followed by the value of the fields Required property.

The reason I’m doing this is because the FieldLabel control emits the * indicator automatically when the field is Required, whereas the FieldDescription control does not.

Next I’ll create the new VerboseListFieldIterator template;

<SharePoint:RenderingTemplate id="VerboseListFieldIterator" runat="server">
	<Template>
		<tr><SharePoint:CompositeField ID="CompositeField1" TemplateName="VerboseCompositeField" runat="server"/></tr>
	</Template>
</SharePoint:RenderingTemplate>

Nothing interesting here, just using the ListFieldIterator control and specifying the VerboseCompositeField template created above.

Finally I’ll create the rendering template for the content type in which we’ll ‘call’ the VerboseCompositeField template to render the fields of the content type;

<SharePoint:RenderingTemplate id="GiftRegisterItemTemplate" runat="server">
	<Template>
		<span id='part1'>
			<style type="text/css">
				SPAN.required_FALSE
				{ display:none; }
			</style>

			<SharePoint:InformationBar ID="InformationBar1" runat="server"/>
			<div id="listFormToolBarTop">
				<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&amp;#160;" runat="server">
						<Template_RightButtons>
							<SharePoint:NextPageButton runat="server"/>
							<SharePoint:SaveButton runat="server"/>
							<SharePoint:GoBackButton runat="server"/>
						</Template_RightButtons>
				</wssuc:ToolBar>
			</div>
			<SharePoint:FormToolBar ID="FormToolBar1" runat="server"/>
			<SharePoint:ItemValidationFailedMessage ID="ItemValidationFailedMessage1" runat="server"/>
			
			<table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" cellspacing="0" width="100%">
				<SharePoint:ChangeContentType ID="ChangeContentType1" runat="server"/>
				<SharePoint:FolderFormFields ID="FolderFormFields1" runat="server"/>

				<SharePoint:ListFieldIterator ID="ListFieldIterator1" TemplateName="VerboseListFieldIterator" runat="server"/>
			
				<SharePoint:ApprovalStatus ID="ApprovalStatus1" runat="server"/>
				<SharePoint:FormComponent ID="FormComponent1" TemplateName="AttachmentRows" runat="server"/>
			</table>

			<table cellpadding="0" cellspacing="0" width="100%">
				<tr>
					<td class="ms-formline">
						<img src="/_layouts/images/blank.gif" width='1' height='1' alt="" />
					</td>
				</tr>
			</table>
			<table cellpadding="0" cellspacing="0" width="100%" style="padding-top: 7px">
				<tr>
					<td width="100%">
						<SharePoint:ItemHiddenVersion ID="ItemHiddenVersion1" runat="server"/>
						<SharePoint:ParentInformationField ID="ParentInformationField1" runat="server"/>
						<SharePoint:InitContentType ID="InitContentType1" runat="server"/>
						<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&amp;#160;" runat="server">
								<Template_Buttons>
									<SharePoint:CreatedModifiedInfo runat="server"/>
								</Template_Buttons>
								<Template_RightButtons>
									<SharePoint:SaveButton runat="server"/>
									<SharePoint:GoBackButton runat="server"/>
								</Template_RightButtons>
						</wssuc:ToolBar>
					</td>
				</tr>
			</table>
		</span>
		<SharePoint:AttachmentUpload ID="AttachmentUpload1" runat="server"/>
	</Template>
</SharePoint:RenderingTemplate>

This is just a copy of the standard ‘ListForm’ rendering template, though I’ve added spacing and line-breaks for clarity.

The 2 changes made are;

  1. Added a STYLE element with a class selector of “.required_FALSE”  to ensure that fields which are optional do not get the required * character.
  2. The ListFieldIterator control specifies that the VerboseListFieldIterator template should be used.
Custom Content Type Rendering Template
Custom Content Type Rendering Template

The last thing that’s needed is to hook the custom rendering template upto the content type using the CAML XmlDocuments element;

<ContentType ID="0x0100AEAAB5189E5A4AC0930A37E275C309DC"
				 Name="Gift Register"
				 Group="RB Content Types"
				 Overwrite="TRUE"
				 Inherits="FALSE"
				 Description="Gift Register Content Type">
	<FieldRefs>
		..omitted..
	</FieldRefs>
	<XmlDocuments>
		<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
			<FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
				<Display>GiftRegisterItemTemplate</Display>
				<Edit>GiftRegisterItemTemplate</Edit>
				<New>GiftRegisterItemTemplate</New>
			</FormTemplates>
		</XmlDocument>
	</XmlDocuments>
</ContentType>

.

Published by

Phil Harding

SharePoint Consultant, Developer, Father, Husband and Climber.

2 thoughts on “Customizing SharePoint List Forms with Content Type Rendering Templates .

  1. Hi Tom, yes this is a 2010 solution using ‘traditional’ server rendering technology, as opposed to the new client side rendering techniques in 2013, great article link BTW, cheers

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