Wednesday, November 21, 2007

SharePoint 2007 - Create field lookup and associated list as a feature

Je suis désolé pour les francophones, mais je dois maintenant m'exprimer en anglais car j'ai mis le code sur Codeplex This feature is an extension of the one from Chris O'Brien (SharePoint 2007 - create lookup fields as a feature), but offer you the ability to define one or more fields and the associated lists within one xml file.Moreover you'll can use these fields in one or more content type. When you'll activate the feature, everything will be build ! Let me explain a bit: First, if you want to have a full explanation of managing lookup column dynamically, you can start with a look on the blog of Chris O'Brien : http://sharepointnutsandbolts.blogspot.com/2007/04/creating-list-based-site-columns-as.html For summarizing, a lookup field is like a choice field but the content comes from a list in the site collection. The main difficulty is that the link between the field and the list is a GUID coming from the instance of the list. This means the GUID is only known when the list has been created. So you can't fix the link in your site column definition. ie:
<Field Type="Lookup" List="{A77FA6BC-8915-458a-914A-92BDDC375726}" ID="{E918A3F4-9E34-4bd2-A621-5F353B4529E2}" Name="KeywordLookup" />
is not possible because you don't know the list GUID. Well, of course you can cheat a bit if you define a list in your site and you retrieve the actual GUID of the instance. But what about moving a site from a test environment to a production environement ? Or from a site collection to another...? The GUID change each time ! The solution proposed by Chris is great. But you must still define a list before activating the feature. And because I'm a little bit lazy, I've tried to improve his solution to one more generic. Let's suppose you want to have a lookup field which contain a list of keywords. These keywords come from a SharePoint list, so you can extend it as you want. Create a new XML file and insert the following code inside. Of course you can have more than one field into this XML file, but I'll use only one for the demo.
<?xml version="1.0" encoding="utf-8" ?><Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Field Type="Lookup" DisplayName="Mots-clés" Mult="TRUE" Required="FALSE" List="Keywords;Mots-Clés" ShowField="Title" UnlimitedLengthInDocumentLibrary="FALSE" Group="TEST" ID="{E918A3F4-9E34-4bd2-A621-5F353B4529E2}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="KeywordLookup" Name="KeywordLookup" /> </Elements>
As you can, this is a classic field definition. Except for one attribute: List. This attribute has two words, Keyword and Mots-Clés. The first one is the internal name of the list template, the second one is the name of the list we'll see in the site. In our case, we gonna create a list named Mots-Clés based on the template internal name Keyword. For a standard Customlist, the internal name is custlist (have a look on 12\TEMPLATE\FEATURES\CustomList\ListTemplates) Why all of this? Because when the feature will be activated, a program will search for a list named Mots-Clés in the site collection. If this list doesn't exist, then the program creates it, based on the list template and the list name you define in the List attribute. Here is the Feature.xml file:
<?xml version="1.0" encoding="utf-8" ?> <Feature Title="Site Column Lookup Initialization" Id="498CB08B-1786-4e34-AD09-F61009A0C6AB" Description="This feature create site columns lookup related to lists" Version="1.0.0.0" Scope="Site" Hidden="FALSE" DefaultResourceFile="TEST" xmlns="http://schemas.microsoft.com/sharepoint/" ReceiverAssembly="Tls.Moss, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5" ReceiverClass="MossSolution.Receivers.LookupFeatureReceiver"> <ActivationDependencies> <ActivationDependency FeatureId="bfda08d3-c7a8-4ade-99d5-86de4ce0ac26"/> </ActivationDependencies> <ElementManifests> <ElementFile Location="LookupFields.xml"/> </ElementManifests> <Properties> <Property Key="ColumnDefinitionPath" Value="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\SiteLookupFields\LookupFields.xml" /> </Properties> </Feature>
In this feature, adapt the event receiver with the name of your assembly. The LookupFields.xml is the file where I put all lookup columns definitions. You can notice one particular property: ColumnDefinitionPath. This is the path where the lookup columns definitions is located. This path will used in the code to retrieve the XML data. I've also added a dependency, because the list template feature must be activated before activating this lookup feature. The tips here is because you defined properly a field, with all the usual behaviors (DisplayName, Show where you want, Readonly...) and a GUID, you can use these fields inside a ContentType! Good news, you have now the opportunity to have a content type with usual field types, PLUS one or more lookup type! The code is available on Codeplex: SharePoint 2007 - Create field lookup and associated list as a feature. There is a folder named Solution which contains the wsp Now, you have to add the solution with stsadm -o addsolution -filename lookupsolution.wsp Then, go to Central Admin / Operation /Solution Management and deploy the solution to the site(s) you want. Then, go to your site settings for activating the collection features, first TEST Keywords then Site Column Lookup Initialization The source code is in _App_code/Receivers. Hope this helps you.

8 comments:

Anonymous said...
This comment has been removed by a blog administrator.
Antoine Pichot said...
This comment has been removed by the author.
naijacoder said...

Hi Antoine,
I'm not sure whether your solution would solve my problem but
I have created 2 columns(Choice field - dropdown list) in a doc lib.
1)Category

2)Types


Currently when users are uploading document they have to select a category then a Types but this 2 fields aren't related.
But what i want is when they choose a Category i want certain fields of Types to populate based on the Category they selected.

I want to to have dependent dropdownlist like a normal asp.net app

Any ideas?

Thanks in advance

Anonymous said...

Excellent work to improve the lookup field code. Did you use particular VS extensions to create the project. I am unable to open the VS project file in VS 05.

Thanks in advance

Antoine Pichot said...

I use VS 2005 Team Edition. It seems you can't this project with VS Tools for Application.

Naijacoder, you'll find a solution in developping a custom field.

Anonymous said...

Hi Antoine,
Thank you for your solution, it's working great and saves me a lot of trouble. But still have an issue when using the resources; the resources are not working and i tried all the folders (12/resources; ...). Below the field declaration, thank you for any tips on this issue.

Field ID="{2227273B-3CA7-4507-9577-20EB18001CE3}"
Name="ServiceField"
StaticName="ServiceField"
SourceID="http://schemas.microsoft.com/sharepoint/v3"
Group="$Resources:SiteColumns,MyGroup;"
DisplayName="$Resources:SiteColumns,LookupField;"
Type="Lookup"
Mult="TRUE"
Required="FALSE"
List="CustomList;Services List"
ShowField="Title"
UnlimitedLengthInDocumentLibrary="FALSE"
DisplaceOnUpgrade="TRUE"
Field

Pierre G. said...

Hi Antoine,
I've deployed the solution, my lists are correctly created and my lookup fields reference these lists. But... when I try to create a item (using a lookup field), even if the dropdown list is correctly populated, I can't save the item :

"Invalid data has been used to update the list item. The field you are trying to update may be read only.".
Did you have the problem?

Thanks!

-------------------

Bonjour Antoine,
J'ai déployé la solution, les listes sont bien créées et les lookup fields associés pointent bien sur ces listes.
Mais... quand je veux créer un item (comportant un lookup field), même si la liste déroulante comporte les bonnes valeurs, je ne peux pas enregistrer :
"Invalid data has been used to update the list item. The field you are trying to update may be read only.".
As-tu déjà rencontré ce problème?

Merci!

Anonymous said...

Thanks for the code, Antoine.
Some thoughts on it.
The most methods can be static. An utility class will be better than inline blocks of code.