Monday, 2 December 2013

Write Once Fields in SharePoint: A Simple Workaround.

Introduction

Recently in a forum, someone had a requirement for making fields on a list read only once an item was added. Out of the box, this isn't possible.

There is a way to achieve a similar result though, using PowerShell to edit the field (or by using CAML properties when declaring the field). This solution doesn't actually set the field for a list item as read only; it just removes the field from the UI (User Interface) so it can't be edited once it's set.

The Desired Result

1. A user can add a new list item, and view all the field.



2. A user can view the list, and see all the fields.



3. The user can edit the list item, but they can only edit a limited number of fields.


How the Solution Works

The solution works by setting boolean values that determine if the field is rendered in the add, view and edit forms. By setting the ShowInNewForm or ShowInEditForm property to false, the user has no way of editing the field (other than to use the DataGrid View, which can optionally be disabled).

The PowerShell Based Solution

The following PowerShell performs the following actions:

  • Removes the "Title", "Item", "Found By" and "DateItemFound" fields from the Edit Form, so that they can't be changed once a list item has been created. 
  • Removes the "AdministrativeNotes" field from the New Form.
  • Disables the DataGrid view

$web = Get-SPWeb "http://devmy131"            
$list = $web.Lists["Lost Property"]            
$field = $list.Fields["Title"]            
$field.ShowInEditForm = $false;            
$field.Update();            
$field = $list.Fields["Item"]            
$field.ShowInEditForm = $false;            
$field.Update();            
$field = $list.Fields["FoundBy"]            
$field.ShowInEditForm = $false;            
$field.Update();            
$field = $list.Fields["DateItemFound"]            
$field.ShowInEditForm = $false;            
$field.Update();            
$field = $list.Fields["AdministrativeNotes"]            
$field.ShowInNewForm = $false;            
$field.Update();            
$list.DisableGridEditing = $true;            
$list.Update();            
$web.Dispose();

The CAML Based Solution

The following CAML can be used in a List Definition (in the Schema.xml file) to set the same properties on the fields. 

<Field ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Type="Text" Name="Title" DisplayName="Title" Required="TRUE" StaticName="Title" ShowInEditForm="FALSE" />

<Field Type="Text" DisplayName="Item" Required="TRUE" ID="{940a19c1-1dd6-4035-9107-32d159d77623}" StaticName="Item" Name="Item" ShowInEditForm="FALSE"/>

<Field Type="User" DisplayName="FoundBy" List="UserInfo" Required="TRUE" ShowField="ImnName" UserSelectionMode="PeopleOnly" UserSelectionScope="0" ID="{56142494-fe1c-48d1-89ac-5ae0901db5e5}" StaticName="FoundBy" Name="FoundBy" ShowInEditForm="FALSE"/>

<Field Type="DateTime" DisplayName="DateItemFound" Required="TRUE" Format="DateTime" FriendlyDisplayFormat="Relative" ID="{7f1ec3a8-ba55-42dd-90ca-47daae6b6cfa}" StaticName="DateItemFound" Name="DateItemFound" ShowInEditForm="FALSE"><Default>[today]</Default></Field>

<Field Type="Note" DisplayName="AdministrativeNotes" Required="FALSE" NumLines="6" RichText="TRUE" RichTextMode="FullHtml" ID="{5c5446a7-85d7-4d34-b883-f41b46968751}" StaticName="Notes" Name="Notes" RestrictedMode="TRUE" AppendOnly="TRUE" ShowInNewForm="FALSE"/>