Article
4 comments

Make custom list forms centralized manageable

SharePoint Designer is a great tool for prototyping but it can really mess up your installation. I want to show a new way / old way how customized form could be make centralised manageable.

For example if you want to create a list form that has certain columns visible to users with a special permission. The fastest way to get there is to create a custom list form is in SharePoint Designer. A tutorial for this can be found at Microsoft Create a custom list form using SharePoint Designer – SharePoint ….

Customising form works great as long as you have a single list and a single form in your portal. If someone saved the list as template and created new instance, the problem start to begin when something needs to be changed in the form.

Let’s make it centralised

In my test case here I have a custom list with a field called “Should be hidden”. This field should be hidden if someone doesn’t have the permission “Manage Lists”. In general this can be accomplished by using a SPSecurityTrimmedControl. The configuration for such a controls looks like this:

<SharePoint:SPSecurityTrimmedControl ID="SecControl" PermissionsString="ManageLists" runat="server">
    <!—something needs to be hidden here -->
</SharePoint:SPSecurityTrimmedControl>

First of all I created a custom list form follow the tutorial by Microsoft.

Sharepoint Designer List Form

Sharepoint Designer List Form

Next I added the security trimmed controls to my field that I wanted to be hidden to users that don’t have the managed lists permission. The code for that looks like this:

<!-- Added Security trimmed control here -->
<SharePoint:SPSecurityTrimmedControl ID="SecControl" PermissionsString="ManageLists" runat="server">
    <tr>
        <td width="190px" valign="top">
            <H3 class="ms-standardheader">
               <nobr>Should be hidden</nobr>
            </H3>
        </td>
        <td width="400px" valign="top">
            <SharePoint:FormField runat="server" id="ff2{$Pos}" ControlMode="Edit" FieldName="Should_x0020_be_x0020_hidden" __designer:bind="{ddwrt:DataBind('u',concat('ff2',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Should_x0020_be_x0020_hidden')}"/>
            <SharePoint:FieldDescription runat="server" id="ff2description{$Pos}" FieldName="Should_x0020_be_x0020_hidden" ControlMode="Edit"/>
        </td>
    </tr>
    <!-- Added Security trimmed control and here -->
</SharePoint:SPSecurityTrimmedControl>

After that addition to the code I tested it and it worked fine. If user doesn’t have the permission to manage lists the field won’t be displayed. Well this doesn’t have much to do with a centralised approach to custom list form but it is a special edit form for list item.

Next that needs to be done is to copy the code that renders the form. This will start with the declaration of an xsl style sheet. The code is embedded into the following tags.

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:dsp="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">
…
</xsl:style>

The complete code for my new form file looks like this:

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:dsp="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">
    <xsl:output method="html" indent="no"/>
    <xsl:decimal-format NaN=""/>
    <xsl:param name="dvt_apos">'</xsl:param>
    <xsl:param name="ManualRefresh"></xsl:param>
    <xsl:variable name="dvt_1_automode">0</xsl:variable>
    <xsl:template match="/" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:dsp="http://schemas.microsoft.com/sharepoint/dsp" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:SharePoint="Microsoft.SharePoint.WebControls">
    <xsl:choose>
        <xsl:when test="($ManualRefresh = 'True')">
            <table width="100%" border="0" cellpadding="0" cellspacing="0">
                <tr>
                    <td valign="top">
                        <xsl:call-template name="dvt_1"/>
                    </td>
                    <td width="1%" valign="top">
                        <img src="/_layouts/images/staticrefresh.gif" id="ManualRefresh" border="0" onclick="javascript: {ddwrt:GenFireServerEvent('__cancel')}" alt="Click here to refresh the dataview."/>
                    </td>
                </tr>
            </table>
        </xsl:when>
        <xsl:otherwise>
            <xsl:call-template name="dvt_1"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
<xsl:template name="dvt_1">
<xsl:variable name="dvt_StyleName">ListForm</xsl:variable>
<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
    <div>
        <span id="part1">
            <table border="0" width="100%">
                <xsl:call-template name="dvt_1.body">
                    <xsl:with-param name="Rows" select="$Rows"/>
                </xsl:call-template>
            </table>
        </span>
        <SharePoint:AttachmentUpload runat="server" ControlMode="Edit"/>
<SharePoint:ItemHiddenVersion runat="server" ControlMode="Edit"/>
    </div>
</xsl:template>
<xsl:template name="dvt_1.body">
    <xsl:param name="Rows"/>
        <tr>
            <td class="ms-toolbar" nowrap="nowrap">
                <table>
                    <tr>
                        <td width="99%" nowrap="nowrap"><IMG SRC="/_layouts/images/blank.gif" width="1" height="18"/>
                        </td>
                        <td class="ms-toolbar" nowrap="nowrap">
                            <SharePoint:SaveButton runat="server" ControlMode="Edit" id="savebutton1"/>
                        </td>
                        <td class="ms-separator"> </td>
                        <td class="ms-toolbar" nowrap="nowrap" align="right">
                            <SharePoint:GoBackButton runat="server" ControlMode="Edit" id="gobackbutton1"/>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
        <tr>
            <td class="ms-toolbar" nowrap="nowrap">
                <SharePoint:FormToolBar runat="server" ControlMode="Edit"/>
            </td>
        </tr>
        <xsl:for-each select="$Rows">
            <xsl:call-template name="dvt_1.rowedit">
                <xsl:with-param name="Pos" select="concat('_', position())" />
            </xsl:call-template>
        </xsl:for-each>
        <tr>
            <td class="ms-toolbar" nowrap="nowrap">
                <table>
                    <tr>
                        <td class="ms-descriptiontext" nowrap="nowrap">
                            <SharePoint:CreatedModifiedInfo ControlMode="Edit" runat="server"/>
                        </td>
                        <td width="99%" nowrap="nowrap">
                            <IMG SRC="/_layouts/images/blank.gif" width="1" height="18"/>
                        </td>
                        <td class="ms-toolbar" nowrap="nowrap">
                            <SharePoint:SaveButton runat="server" ControlMode="Edit" id="savebutton2"/>
                        </td>
                        <td class="ms-separator"> </td>
                        <td class="ms-toolbar" nowrap="nowrap" align="right">
                            <SharePoint:GoBackButton runat="server" ControlMode="Edit" id="gobackbutton2"/>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
</xsl:template>
<xsl:template name="dvt_1.rowedit">
    <xsl:param name="Pos" select="position()"/>
        <tr>
            <td>
                <table border="0" cellspacing="0" width="100%">
                    <tr>
                        <td width="190px" valign="top" class="ms-formlabel">
                            <H3 class="ms-standardheader">
                                <nobr>Title<span class="ms-formvalidation"> *</span></nobr>
                            </H3>
                        </td>
                        <td width="400px" valign="top" class="ms-formbody">
                            <SharePoint:FormField runat="server" id="ff1{$Pos}" ControlMode="Edit" FieldName="Title" __designer:bind="{ddwrt:DataBind('u',concat('ff1',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Title')}"/>
                            <SharePoint:FieldDescription runat="server" id="ff1description{$Pos}" FieldName="Title" ControlMode="Edit"/>
                        </td>
                    </tr>
                    <!-- Added Security trimmed control here -->
                    <SharePoint:SPSecurityTrimmedControl ID="SecControl" PermissionsString="ManageLists" runat="server">
                <tr>
                    <td width="190px" valign="top" class="ms-formlabel">
                        <H3 class="ms-standardheader">
                            <nobr>Should be hidden</nobr>
                        </H3>
                    </td>
                    <td width="400px" valign="top" class="ms-formbody">
                        <SharePoint:FormField runat="server" id="ff2{$Pos}" ControlMode="Edit" FieldName="Should_x0020_be_x0020_hidden" __designer:bind="{ddwrt:DataBind('u',concat('ff2',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Should_x0020_be_x0020_hidden')}"/>
                        <SharePoint:FieldDescription runat="server" id="ff2description{$Pos}" FieldName="Should_x0020_be_x0020_hidden" ControlMode="Edit"/>
                    </td>
                </tr>
                <!-- Added Security trimmed control and here -->
            </SharePoint:SPSecurityTrimmedControl>
                <tr id="idAttachmentsRow">
                    <td nowrap="true" valign="top" width="20%">
                        <SharePoint:FieldLabel ControlMode="Edit" FieldName="Attachments" runat="server"/>
                    </td>
                    <td valign="top" width="80%">
                        <SharePoint:FormField runat="server" id="AttachmentsField" ControlMode="Edit" FieldName="Attachments" __designer:bind="{ddwrt:DataBind('u','AttachmentsField','Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Attachments')}"/>
            <script>
                var elm = document.getElementById(&quot;idAttachmentsTable&quot;);
                if (elm == null || elm.rows.length == 0)
                    document.getElementById(&quot;idAttachmentsRow&quot;).style.display=&apos;none&apos;;
            </script>
                    </td>
                </tr>
                <xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
                <tr>
                    <td colspan="99">
                        <span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
                    </td>
                </tr>
            </xsl:if>
            </table>
        </td>
    </tr>
    </xsl:template>
</xsl:stylesheet>

 

I stored this to a file named “Form.xsl”. In SharePoint Designer and mark the customised data form web part and select from the web part tab the properties of the web part. Empty the XSL Editor Field and instead link to the form.xsl File in the style library. The property for than can be found under the miscellaneous option.

Miscellaneous Web Part Properties

Miscellaneous Web Part Properties

Save the file and close SharePoint Designer. Go back to the list and edit an existing list item the new custom form will be loaded directly from the style library.

Form loaded from style library

Form loaded from style library

To proof this I edited the form.xsl file in notepad and added a nice yellow background to the “Should be hidden” field. Then I uploaded it back to SharePoint.

Changed xsl form

Changed xsl form

As you see all works fine with an external list form stored in style library.

Conclusion

As always plan your customisations to SharePoint well. Central managed list forms can do a great job to certain lists. The link to the file will be stored even if the list will be saved as a template. It doesn’t have to be always a visual studio solution to get things done. The most effort on this is that this saves a lot time on customizing list in a portal.

I used it in a couple of projects. It works well and normal web designer can do any changes to the list forms. The xsl file and the configuration of the web part can also be provisioned by code. I think there are endless options to use this SharePoint feature.

This customisation is also supported and saves a lot of headache on finding out where lists are that are customised with a special form. One simple file can change a lot of forms in a portal.

This scenario was also supported by SharePoint 2007.