Updating content types using SharePoint Web Services (SPServices)

When you deploy an updated content type which is created from code and have new fields, your changes won’t automatically be pushed to children that inherit from your content type. This is only the case when you have created your content type using code. In the sandbox solution, I’m using the SharePoint Web Services to add new fields to content types that inherit from the updated content type.

Why the web services? With the push from Microsoft to go more and more client side, I found it a challenge to not do something with simply a farm solution or a server-side script. During the development of the web part, I’ve found 2 annoyances by using the SPServices library and jQuery/SharePoint:

  1. SPServices says every method name is unique. This is not true. There’s a method “UpdateContentType” for both the Lists.asmx and the Webs.asmx. Due to this overlooked bug, the call will always be directed to the Webs.asmx web service. I’ve modified the SPServices js file to comment out the WSops.UpdateContentType method for Webs.
  2. jQuery will always put your generated attributes to lower case. The web services are case-sensitive as you can see from the following screenshot (taken from STSSOAP.DLL, decompiled with ILSpy)
    caseSensitive

The web part itself is pretty straight forward. You’ll get a list of content types with update links.

content type updater webpart

When using firebug or another web dev tool, you can track all the calls that are made to the Webs.asmx & Lists.asmx

content type updater console window

I’ve deployed a custom content type to my site, created a list with that content type and then made an update to the site content type. As you can see there’s a column missing from the list content type:

site content type

list content type

After I click on “Update” next to “CustomContentType”, the script will detect a difference between these two and update accordingly:

soap call new fields

And the updated list content type:

updated list content type

All in all I’m pretty happy with the result. You can do a lot with just the web services from SharePoint, but they take some time to get used to. Also the documentation isn’t always great as for instance they mention to use <FieldRefs> while in the source code of the web service itself there’s only a parse of the <Fields> tag.

For the full source, or if you want to download and test the web part itself, you can go to CodePlex.

Advertisements

Lookup Field localization not working when using ContentTypeBinding

Whilst working with lookup fields, I noticed something strange when you separated the Fields and ContentType from your list and you try to use localization. Separating your content type and fields from your list basically means that you no longer work with a custom list definition, but you use ContentTypeBinding on a list instance to create your list.

Here’s an example on how the project is set up:

lookupFieldLocalizationProject

The red arrows point to the lookup list where I use the ContentType “LookUpContentType”, where a lookup field is referenced. This lookup field resides in the “Fields” element:

“Fields” Elements.xml

<?<span class="hiddenSpellError">xml version="1.0" encoding="utf-8"?>
xmlns="http://schemas.microsoft.com/sharepoint/">
  <Field Name="LookUpFieldInElements"
  Required="TRUE"
  ID="{32A4FE06-2745-40D0-B92C-76A58B16C7B0}"
  Type="Lookup"
  Mult="FALSE"
  Overwrite="TRUE"
  List="Lists/Source"
  ShowField="Title"
DisplayName="$Resources:lookupfield,LookUp;"
  StaticName="LookUpFieldInElements"
  />
</Elements>

“LookUpContentType” Elements.xml

<?xml version="1.0" encoding="utf-8"?>
xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- Parent <span class="hiddenSpellError" pre="Parent ">ContentType</span>: Item (0x01) -->
<ContentType ID="0x01002846E06F521348B79F631D4D9E6A07CC" Name="LookUpContentType" Group="Custom Content Types" Description="My Content Type" Inherits="TRUE" Version="0">
    <FieldRefs>
<FieldRef ID="{32A4FE06-2745-40D0-B92C-76A58B16C7B0}" Name="LookUpFieldInElements" Required="TRUE" />
    </FieldRefs>
ContentType>
</Elements>

“LookUpListCTInstance” Elements.xml

<?xml version="1.0" encoding="utf-8"?>
xmlns="http://schemas.microsoft.com/sharepoint/">
<ListInstance
Title="LookUpListCT"
    OnQuickLaunch="TRUE"
    TemplateType="100"
    Url="Lists/LookUpListCT"
Description="My List Instance with ContentTypeBinding"
    FeatureId="00bfea71-de22-43b2-a848-c05709900100">
  </ListInstance>
<ContentTypeBinding ContentTypeId="0x01002846E06F521348B79F631D4D9E6A07CC" ListUrl="Lists/LookupListCT" />
</Elements>

The blue arrows point to a regular list definition which has a list instance included.

The Schema.xml of the “LookupList” list definition

<ContentTypes>
      <ContentType ID="0x0100468fd589c1da4592929a6768ac144020" Name="ListFieldsContentType">
        <FieldRefs>
<FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" />
<FieldRef ID="{a51cabb2-7594-41db-8523-ea5de71e6202}" Name="LookUp" />
        </FieldRefs>
      </ContentType>
    </ContentTypes>
    <Fields>
      <Field
        Name="LookUp"
        ID="{a51cabb2-7594-41db-8523-ea5de71e6202}"
DisplayName="$Resources:lookupfield,LookUp;"
        Type="Lookup"
        List="Lists/Source"
        ShowField="Title" />

When you take a look at the DisplayNames of both the LookupFields residing in Schema.xml and “Fields” Elements.xml, you’ll see that the value holds “$Resources:lookupfield,LookUp;”. So we’re trying to localize the LookupField’s column name.

I’ve added the following resource files where I can add my translations:

lookupFieldLocalizationResourceFiles

lookupfield.resx

<data name="LookUp" xml:space="preserve">
  <value>LookUp</value>
</data>

lookupfield.en-US.resx

<data name="LookUp" xml:space="preserve">
  <value>[ENG] LookUp</value>
</data>

lookupfield.nl-NL.resx

<data name="LookUp" xml:space="preserve">
  <value>[NL] LookUp</value>
</data>

lookupfield.fr-FR.resx

<data name="LookUp" xml:space="preserve">
  <value>[FR] LookUp</value>
</data>

Looks great! Let’s check out the result on our SharePoint lists:

lookupFieldLocalizationDutchLocalization

lookupFieldLocalizationDutchLocalizationCT

Apparently there’s a bug when separating your LookupField from your Schema.xml where it will only use the English localization. So whenever you want to use LookupFields in custom lists, use the list definition way!

Creating a cross site lookup field without code

There’s a high demand for using cross site lookup fields. Most solutions offered include deploying a solution or writing your own code. There is, however, a simple method for creating a cross site lookup field by using SharePoint’s own GUI.

In the following example I use 2 sites, http://sharepoint/Site with a custom list named “Values”. I added 3 items in the list as sample data:

main site

The other site is a subsite from the previous one, http://sharepoint/Site/Subsite. Here I added a custom list named “Using Lookup”:

sub site

Browse back to the main site, in my example http://sharepoint/Site, and click on Site Actions, Site Settings:

Site Actions Site Settings

On the site settings page navigate to the site columns gallery:

Site columns gallery

Click on the create button to create a new site column:

create new site column

Fill in a desired name:

site lookup column

Next, select the custom list “Values” at the properties and whatever you need to lookup:

site lookup column properties

Click on OK and navigate to your subsite’s custom list, in my example the list “Using Lookup”. Open up the list settings:

using lookup list settings

At the columns settings, click on “Add from existing site columns”:

list settings columns

Select the “Lookup Values” column and press the add button:

add lookup values column

Click OK, navigate to the list “Using Lookup” and add a new item. The lookup values from the topsite are now selectable!

new lookup item

As far as constraints go, they’re the same as every custom site column.