Friday, December 11, 2009

SharePoint Computed Site Columns, Site & List Content Types

I was creating a customized CQWP rollup for linking to applications and tools from a MOSS site, and used the OpenInNewWindow attribute in my custom ItemStyle.xsl file to get target="_blank" in the links. In addition, I wanted the "open in new window" functionality in the lists storing the actual links. Unfortunately, this is not available ootb in SharePoint lists using the URL site column.

So I took the list field CAML definitions from Andrew Connell's Adding "OpenInNewWindow" option to SharePoint Links lists post and modified them into new site columns:

<Field Type="Boolean" Name="OpenInNewWindow" DisplayName="Open in New Window" Required="TRUE" Group="KjellSJ site columns" ID="{2F88664E-D2FB-40da-B962-C454C895074F}" SourceID="http://schemas.microsoft.com/sharepoint/v3" />

<Field ID="{7CC38078-C7F4-4c1a-B6F6-D681D4079E3B}"
Type="Computed"
Group="KjellSJ site columns"
Name="URLNewWindowLink" DisplayName="URL (new window link)"
ShowInNewForm="FALSE" ShowInFileDlg="FALSE" ShowInEditForm="FALSE"
Filterable="FALSE" Sortable="FALSE"
SourceID=http://schemas.microsoft.com/sharepoint/v3/fields
StaticName="URLNewWindowLink">
<FieldRefs>
<FieldRef ID="{c29e077d-f466-4d8e-8bbe-72b66c5f205c}" Name="URL"/>
<FieldRef ID="{2F88664E-D2FB-40da-B962-C454C895074F}" Name="OpenInNewWindow"/>
</FieldRefs>
<DisplayPattern>
<HTML><![CDATA[<A HREF="]]></HTML>
<Column Name="URL" HTMLEncode="TRUE"/>
<HTML><![CDATA["]]></HTML>
<Switch>
<Expr><Column Name="OpenInNewWindow"/></Expr>
<Case Value="1"> <HTML><![CDATA[ target="_blank"]]></HTML> </Case>
</Switch>
<HTML><![CDATA[>]]></HTML>
<Switch>
<Expr><Column2 Name="URL"/></Expr>
<Case Value=""> <Column Name="URL" HTMLEncode="TRUE"/> </Case>
<Default> <Column2 Name="URL" HTMLEncode="TRUE"/> </Default>
</Switch>
<HTML><![CDATA[</A>]]></HTML>
</DisplayPattern>
</Field>

I added the new site columns to a site content type, deployed and checked the results. The computed site column was not shown in the Site Columns Gallery, but neither are any of the ootb computed site columns. Alas, computed columns are shown when looking at content types, but cannot be added, updated or removed. Check e.g. the Picture Size field in the ootb Picture content type, which is the computed ImageSize site column. You can still see the computed site column by opening the OpenInNewWindow column and just changing the &field= name in the query string to URLNewWindowLink - or use SharePoint Manager 2007.

With the new fields added to the site content type, I created a custom list from Site Settings and changed the list content type from Item to my AppsToolsList site content type. To my surprise, the computed site column was not added to the list, and I confirmed that it had not been added to the list content type either by using SharePoint Manager 2007.

The sad thing about computed columns being hidden in all site column pickers is that you cannot add it using "Add from existing site columns" in List Settings. It seems the only way of getting a computed field provisioned to a list is by adding it as a CAML list definition field.

Knowing that there are quirks when provisioning new list content types from site content types (see List Content Type Fields & Forms: CAML vs Code), I used the object model to provision the computed site column by adding it using code:

urlNewWindowLink.Title = "URL";
list.Fields.AddFieldAsXml(urlNewWindowLink.SchemaXml, true, SPAddFieldOptions.AddToNoContentType);

The computed column is added to the list's field collection and to its default view, but not to the list content type. The DisplayPattern CAML works fine, but only as long as you don't rename the computed field using List Settings > Edit Column (using the &field= trick). Doing so will change the DisplayName of the field, but also remove the FieldRefs from the list field's SchemaXml. The computed field rendering will still work as long as the fields used in the DisplayPattern CAML is in the view, but remove them from the view and you'll get this error:

<!-- #RENDER FAILED -->

You can always implement a list definition instead of using code, just remember that you need to duplicate all site column field definitions in the list template due to the way CAML provisioning works.

No comments: