Tom Clarkson is a SharePoint consultant and entrepreneur based in Sydney, Australia.

Contact Details

Links



Recent Searches



Archives




Past Posts







RSS Feed

Default Values for Lookups with a Custom Field Type

SharePoint 2007
Friday December 7 2007
The requirement:
The metadata attached to an uploaded document is fairly complex, and users should not need to specify values manually. Instead the values should be set based on where the user clicked to upload the document.
 
The solution:
A custom field type is created that extends the out of box lookup field and reads values from the query string. Standard query string parameters will work well for adding list items, but not for uploads as the upload page will not pass values through to the edit form. For uploads we can add the same properties to the Source query string parameter, which is used to redirect after the item is saved. To do this properly you would need a custom script to set the source parameter, but it is easily tested by adding the parameters to the address bar before clicking the upload button on a standard list page.
 
To create a custom field type, you need at least two files on top of the standard solution package structure - an xml file with a name like fldtypes_LookupDefaultFromQuery.xml in 12\TEMPLATE\XML and a class that extends SPField.
 
The class itself is fairly simple - just extend SPFieldLookup to override SPFieldLookup. Only default value needs to be changed - we can use the existing edit controls for both the value and the field properties. The value to use will be the id of the item to select in the lookup. 
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Web.UI;
using System.Web.UI.WebControls;


namespace LookupFieldTypes
{
    public class LookupDefaultFromQuery : SPFieldLookup
    {

        public LookupDefaultFromQuery(
SPFieldCollection fields,
string fieldName) : base(fields, fieldName) { } public LookupDefaultFromQuery(
SPFieldCollection fields,
string typeName,
string displayName) : base(fields, typeName, displayName) { } public override string DefaultValue { get { try { System.Collections.Specialized.NameValueCollection qs =
System.Web.HttpContext.Current.Request.QueryString; // First look for the value in the page query string string dv = qs["Selected" + this.InternalName]; if (!string.IsNullOrEmpty(dv)) { return dv; } // if the value wasn't found, try the source url string source = qs["Source"]; Uri uri = new Uri(source); return System.Web.HttpUtility.ParseQueryString(uri.Query)
["Selected" + this.InternalName]; } catch (Exception ex) { return base.DefaultValue; } } set { base.DefaultValue = value; } } } }
The xml file is a little harder to get right, since there is no useful documentation available and copying any of the out of box fieldtype declarations from fldtypes.xml doesn't work. Bits that seem to be particularly important:
  • FieldTypeClass needs to point to the custom class above. Even if that class doesn't override anything from the base class, specifying SPFieldLookup as the out of box lookup field does will not work. It even stops the standard lookup field from working properly.
  • FieldEditorUserControl is the control that appears when creating a new field. The out of box control can be used, although there are issues around switching to multiple selection that aren't handled by this code.
  • SQLType needs to be int to store the id. Various things break if it isn't specified.
  • InternalType is what allows the LookupColumn and URL cmd="Lookup" elements in the renderpatterns to work properly.
  • RenderPattern elements are copied from the Lookup field type in fldtypes.xml and are excluded from this post because they are really long and complex. You can make changes to them if you want, but the only documentation I have seen is the view schema at http://msdn2.microsoft.com/en-us/library/ms439798.aspx, which is only slightly helpful.
 
<?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
  <FieldType>
    <Field Name="TypeName">LookupDefaultFromQuery</Field>
    <Field Name="TypeDisplayName">LookupDefaultFromQuery</Field>
    <Field Name="TypeShortDescription">Lookup with default value from query string</Field>
    <Field Name="UserCreatable">TRUE</Field>
    <Field Name="FieldTypeClass">LookupFieldTypes.LookupDefaultFromQuery, LookupFieldTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5296a18ab0247d05</Field>
    <Field Name="FieldEditorUserControl">/_controltemplates/LookupFieldEditor.ascx</Field>
    <Field Name="SQLType">int</Field>
    <Field Name="InternalType">Lookup</Field>
    <Field Name="Sortable">TRUE</Field>
    <Field Name="Filterable">TRUE</Field>

    <RenderPattern Name="HeaderPattern">
...
    </RenderPattern>
 
  </FieldType>
</FieldTypes>
 
 

Comments

On 16 Sep 2008 01:32, Nguyen Van Minh said:
Good idea! Thank you!
On 20 Sep 2008 08:53, spmikey said:
Thanks for your excellent article, but does it break the rules? Here's what Microsoft says: http://msdn.microsoft.com/en-us/library/aa544201.aspx

ParentType:
<Field Name="ParentType"></Field>. It must never be empty in your custom field types. All custom types inherit from another type.

InternalType:
 Optional String. Represents an internal base type. Do not use a <Field Name="InternalType"> element in your custom field type definitions.

SQLType:
 Optional String. Represents the SQL data type that will be used to store the data in the content database. Do not use a <Field Name="SQLType"> element in your custom field type definitions.
On 20 Sep 2008 10:34, Tom Clarkson said:
I wouldn't worry too much about those rules. They aren't in the list of things that make your environment unsupported, so I read them as "don't use this unless you know what you are doing". This sort of customisation is often closer to developing internal SharePoint code than anything else. 

Besides, it doesn't work without using those "internal use only" properties - Most of the functionality relies on reusing stuff from the standard lookup field, and I remember looking around in reflector and finding that in several places it is hardcoded to check if InternalType is "Lookup".
On 31 Oct 2008 10:43, Mike said:
I'm wondering how I could filter by a parameter in the query string.

For Example:

Column To Filter Lookup On:  ProductID
Type of Operator:  Equal To
Value to Filter Lookup On:  <ProductID> - from http://sharepointsite/products.aspx?ProductID=101

Is this what you are doing here? I am fairly new and trying to understand how to duplicate what you are doing.

Thanks in advance.
On 31 Oct 2008 03:16, Tom Clarkson said:
This code is setting the default value rather than the available values, but you can use a similar approach for filtering - you could override the rendering of the dropdown so only valid values are included.

If you're just thinking list filtering, the query string parameters FilterField1/FilterValue1 may be useful.

On 01 Nov 2008 03:45, Mike said:
I was thinking along the lines of filtering the available values to only one value that I pass in the querystring. I would think that you would need to apply it to the CAML query of the lookup somehow, just not exactly sure how to do it :)
On 01 Nov 2008 07:50, Mike said:
I was thinking along the lines of filtering the available values to only one value that I pass in the querystring. I would think that you would need to apply it to the CAML query of the lookup somehow, just not exactly sure how to do it :)
On 03 Nov 2008 10:57, Tom Clarkson said:
I don't think the query used to populate the lookups is exposed - I think the closest you will get is getting access to the dropdown control after it is generated and filter that using whatever filter you need.
On 19 Nov 2008 01:18, Ian Cooper said:
I've been creating my own Custom Field based on SPFieldLook, everything is working great, except i cannot use this new Field in SharePoint Designer, it's recognised as a "String" not "List Item ID".  Can anybody help?
On 26 Feb 2009 02:02, said:
On 16 Apr 2009 04:47, Vadim Dzyuban said:
Hi Tom,
Sharepoint lookup field mapping to a remote lookup list

Doing research and experimenting with a lookup field I’ve found that a lookup field (a site column which gets their data from a list) and a lookup list (from which a lookup field gets their data) must belong to the same site (or different sites if sites are a parent and child) within a site collection.  There are also the cross-sites lookup field solutions where a lookup field and a lookup list might belong to different sites but again within the same website/site collection. All these known implementations do not allow separate a lookup field and a lookup list meaning to have them on different web applications and working together. 
Is this correct or am I missing something? 

There might be another scenario where a lookup field should be deployed on a few hundred client’s sites and these clients’ lookup fields must get their data from a remote lookup list being resided on separate admin web application. In this case remote lookup list might be maintained at one central place (admin web app) and feeds updated data for all clients’ lookup fields. The point here is to avoid creation of hundreds instances of a remote lookup list on the clients’ sites. Client sites’ lookup fields should map directly to a remote lookup list being resided on separate admin web application.     
Any idea, advise, discussion or references about a lookup field mapping to a remote lookup list implementation using CAML/C#/webservices will be appreciated.

Thanks.
Vadim. 

Leave a comment