The very first MOSS 2007 project I worked on started last year, during the second beta release. There wasn’t a lot of information available yet on how to use the product, so I had to make a few discoveries on my own. Of them, this has turned out to be the most useful, and I still haven’t seen a lot written about it (although I haven’t had much time to keep up on blog reading lately, so I’m not claiming to be the only person who has discovered this technique).

The project had a requirement for a summary links field control with a heading over it, something like:

Useful Links

Here was the stickler requirement: the heading needed to be hidden if there were no links in the field control. One approach was to hard code the heading in the page layout and use JavaScript to dynamically hide the heading element if the field control was empty. Not very elegant, and wouldn’t work if someone happened to have JavaScript functionality turned off in their web browser. Another recommended approach was to create a page layout for each possible combination of hidden and displayed fields– an option that quickly becomes unmanageable the more optional fields you have.

I was really interested in the DisplayTemplate property available on all the out of box field controls, but at first I had no idea how to use it. Experimentation with the property showed that populating the DisplayTemplate for a simple text field worked like a charm, but for things like Summary Links & Rich HTML Content, it looked like the field controls just completely ignored the DisplayTemplate contents.

How annoying!

A couple of new articles cropped up in the SDK around the same time that gave me a big clue and I was able to work out the rest even though the documentation is still a little… incomplete.

I started with the vaguely useful “How to: Create a Custom Field Control“. Obviously if I wanted a field control that both displayed summary links data and used the DisplayTemplate property, I was going to have to write my own. That article got me started on writing a custom field control, but I still wasn’t 100% sure how I could implement the DisplayTemplate itself. However, one clue was that you could create an .ascx file that would allow you to template a field control.

Since we were dealing with .ascx files, I had a look in the 12\TEMPLATE\CONTROLTEMPLATES folder and examined DefaultTemplates.ascx file for more information. This had a lot of markup in it that went something like:


<SharePoint:RenderingTemplate ID="*unique identifier*" runat="server">
<Template>
*Markup stuff here*
</Template>
</SharePoint:RenderingTemplate>

So I set up a new .ascx file with the above and my own markup & copied that to CONTROLTEMPLATES. It looked more or less like this:


<SharePoint:RenderingTemplate ID="CustomLabelField" runat="server">
<Template>
<div class="field_section" id="field_wrapper" runat="server">
<h1><SharePoint:FieldProperty ID="FieldProperty1" PropertyName="Title" runat="server"/></h1>
</div>
</Template>
</SharePoint:RenderingTemplate>

I then created an appropriate feature.xml and elements.xml and installed my new control as a feature by following the documentation here:
http://msdn2.microsoft.com/en-us/library/ms470880.aspx

Creating the feature centralised my DisplayTemplate so if I ever needed to modify the markup, I wouldn’t have to modify every single field control in every single page layout.

The next step was to create my own custom field control that worked out what type of field control it should be displaying and dynamically adding it into my field_wrapper div element before rendering, and then checking the ItemFieldValue for whether my field_wrapper div should be visible or not. For that I used the new How to: Create a Custom Field Control article for ideas. The key was using the TemplateContainer property to find the server side controls in my template that I needed to populate, e.g.

protected override void CreateChildControls() {
base.CreateChildControls();
// Check in the template for a div that wraps around all
// the content. The visibility on this div will be switched
// off if the field is empty of content.
this._divWrapper = this.TemplateContainer.FindControl("field_wrapper") as HtmlGenericControl;
// add in the field's display label, determine visibility for the wrapper div
...
}

After adding my new field control as a SafeControl to the web application, I can add the following into my page layout file:

<%@ Register Tagprefix="Custom" Namespace="Andrea.SharePoint.CustomControls" Assembly="Andrea.SharePoint.Custom" %>
...
<Custom:FieldWrapperFieldControl runat="server" FieldName="Useful_x0020_Links" DisplayTemplateName="CustomLabelField" />

Et voila! I had a custom field control that would “switch off” in published mode when empty, was editable and behaved exactly as the original field control for the type of field being displayed, and would display nicely formatted output with the field’s label as a heading tag above the field.

Hope you found this article useful.

6 Responses to “Templating field controls in MOSS page layouts”

  1. Cara Faye said

    Hi Andrea
    Thanks for a great post.
    I’m creating a new page layout in SharePoint Designer and I need to customize the look of the Rich Image field control so that it always has a particular border, and if we upgrade the look and feel, we don’t have to go through every page changing border colour. However I am unable to customize the field controls in Designer – could you assist?

  2. Hi Cara,

    The simplest answer for this is to use a CSS class to style your field control. That is precisely what cascading style sheets are designed for.

    If you want to use the method described in this post, simply make sure that you assign a CSS class to an appropriate element in the rendering template.

    Alternatively, you can also apply a stylesheet class directly to a field control as well using the CssClass attribute of the control.

    You can then create a centrally stored .css file with a style definition for that class, including border width, style, and colour. When you update the style definition, every element using that class will be updated instantaneously.

    If you want to learn more about CSS, I’d recommend this primer at W3 Schools: http://www.w3schools.com/web/web_css.asp

  3. Cara Faye said

    Thanks for the response. The CSS classes make the most sense.
    Subsequent to posting the question we’ve discovered that we need to use more than one site definition in order to achieve the branding needs of the company; I’m assuming it’s reasonably simple to add CSS classes to each site definition… ?

  4. Hi Cara,

    There are a couple of ways you can apply your own CSS stylesheets in SharePoint. The most straightforward way to do this is:

    1. Upload the .css file into the Style Library document library at the site root of a Publishing web site
    2. In the site settings, go to the “Master Page” option under “Look and Feel” and specify your uploaded CSS file as the Alternate CSS URL for the site.

    You can then override the default CSS in MOSS to your heart’s content– I’d recommend reviewing Heather Solomon’s very handy CSS chart for that: http://www.heathersolomon.com/content/sp07cssreference.htm

    Another method is to modify the .master file to include a tag (inelegant, but works for testing purpose) or a to a .css file. You can further modify the master page & page layouts to include your own custom CSS classes for an extreme break from default SharePoint styles.

  5. Gerald said

    Hello Andrea,

    is it possible that you send me the source code files becouse I need the same functionality for a project.

    Thanks in advance,

    regards
    Gerald

  6. Tom said

    Hi Andrea,

    I wonder if you can point me in the right direction. I’ve created a CustomField Type and followed all the steps from various resources on the net. I can use my control within site settings and attach it to a content type. However, when I come to use the control within a pagelayout, my page errors with: Unknown Server tag.

    I have a directive at the top of my page which registers the control on the page, which I can presume is correct as this errors if I enter incorrect information. I have also included a Safe Control entry. I’ve used reflector to ascertain the correct assembly versions etc and these appear to be correct in all the places necessary.

    Any ideas?

Leave a Reply