From SharePoint Magazine: Variations in Multiselect Controls in Different SharePoint Language Versions

[SharePoint Magazine date=”December 23, 2010″]

Consistency in one’s development practices is a critical part of generating reliable, maintainable code. Most large software contains some inconsistencies, but in your development efforts with SharePoint, you should try your best not to introduce any inconsistencies of your own.

In this article, I’ll show you the effect of one of SharePoint’s little inconsistencies and why it was an issue in my development of SPServices.

If you’ve ever tried to implement jQuery in multi-language SharePoint solutions, you really need to pay attention.

Recently, I had to fix something in SPServices for someone who was using the German version of SharePoint 2010. The issue was with the way some Document Object Model (DOM) elements are identified in the German version. In fact, I’ve run into these inconsistencies before. These inconsistencies can add up to larger bugs not just for people like me who are trying to understand the DOM to make script work, but they probably contribute to issues that arise from installing service packs, hotfixes, and so on.

Whomever did the translations internally to some of the different languages wasn’t consistent in how they made some of the changes to things such as DOM element IDs. The specific case here is with multiselect columns. This inconsistency is the same whether you’re working with SharePoint 2007 or SharePoint 2010.

Anatomy of a Multiselect Column’s Markup

When SharePoint renders the rather complex controls for a multi-select column, it looks something like the image shown here. This is an example from a SharePoint 2010 installation, but it looks basically the same as it does in SharePoint 2007. The control is also the same whether you’re working with a NewForm or an EditForm.

image_thumb4The City column is a multiselect Lookup column. This seemingly simple type of column actually consists of many different DOM elements as well as some fairly complicated underlying JavaScript. (Yes, Virginia, SharePoint uses a lot of JavaScript right out of the box.)

Here is a snapshot of the DOM for the control at a high level:

SNAGHTML4bbbec4_thumbLet’s break that markup down into its components to see how it works:

SNAGHTML4bb3451_thumbBefore we even get to anything visual, there is a set of hidden INPUT elements that the scripts use to manage things. Each of the three INPUT elements have long IDs preceded by [long GUID-based stuff] and ending with the names in the following table:

MultiLookupPicker Used to store the currently selected set of values, using the odd separator ‘|t’, as in ’1|tAbington|t2|tActon|t3|tAcushnet’.
MultiLookupPicker_data Stores the full set of allowable values, like this ’1|tAbington|t |t |t2|tActon|t |t |t3|tAcushnet|t |t ‘ (and so on). It’s not clear why there are extra separators in this one.
MultiLookupPicker_initial Stores the initial value of the column as of page load.

Next comes a table that contains the visual elements of the control:

image_thumb5The left side of the control is a SELECT that has some script attached to its dblclick and change events. The important thing we need to know about this SELECT element is its title. In an English installation, the title=”City possible values”. It’s the column name followed by ‘ possible values’.

<TD class=ms-input>
  <SELECT style="WIDTH: 143px; HEIGHT: 125px; OVERFLOW: scroll" id=ctl00_m_g_856b69b7_94a3_499a_af52_e1789266b73a_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_SelectCandidate title="City possible values" ondblclick="GipAddSelectedItems(ctl00_m_g_856b69b7_94a3_499a_af52_e1789266b73a_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); return false" multiple onchange=GipSelectCandidateItems(ctl00_m_g_856b69b7_94a3_499a_af52_e1789266b73a_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); name=ctl00$m$g_856b69b7_94a3_499a_af52_e1789266b73a$ctl00$ctl05$ctl02$ctl00$ctl00$ctl04$ctl00$ctl00$SelectCandidate>
    <OPTION title=Abington selected value=1>Abington</OPTION>
    <OPTION title=Acton value=2>Acton</OPTION>
    <OPTION title=Acushnet value=3>Acushnet</OPTION>
    <OPTION title=Wrentham value=350>Wrentham</OPTION>
    <OPTION title=Yarmouth value=351>Yarmouth</OPTION>

Next comes a 10-pixel-wide spacer TD. It’s not very interesting, but I mention it for completeness. Usually you’d probably do spacing like this in the CSS rather than having a dedicated TD for it.

<td style="padding-left: 10px;"/>


Next come the two buttons. Both buttons have some script attached to their click event that manages the movement of the values between the left and right boxes.

<TD class=ms-input vAlign=center align=middle>
  <BUTTON id=ctl00_m_g_856b69b7_94a3_499a_af52_e1789266b73a_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_AddButton class=ms-ButtonHeightWidth onclick="GipAddSelectedItems(ctl00_m_g_856b69b7_94a3_499a_af52_e1789266b73a_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); return false" type=submit>Add &gt;</BUTTON>
  <BUTTON id=ctl00_m_g_856b69b7_94a3_499a_af52_e1789266b73a_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_RemoveButton class=ms-ButtonHeightWidth disabled onclick="GipRemoveSelectedItems(ctl00_m_g_856b69b7_94a3_499a_af52_e1789266b73a_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); return false" type=submit>&lt; Remove</BUTTON>


Now another 10-pixel-wide spacer TD:


And finally, we have the right side box. Like the left side, this is also a SELECT with some script attached to its dblclick and change events. The important thing we need to know about this SELECT element to work with it is its title. In an English installation, title=”City selected values”. It’s the column name followed by ‘ selected values’.

<TD class=ms-input>
  <SELECT style="WIDTH: 143px; HEIGHT: 125px; OVERFLOW: scroll" id=ctl00_m_g_517395ec_085b_47db_b888_b55773e76d86_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_SelectResult title="City selected values" ondblclick="GipRemoveSelectedItems(ctl00_m_g_517395ec_085b_47db_b888_b55773e76d86_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); return false" multiple onchange=GipSelectResultItems(ctl00_m_g_517395ec_085b_47db_b888_b55773e76d86_ctl00_ctl05_ctl02_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); name=ctl00$m$g_517395ec_085b_47db_b888_b55773e76d86$ctl00$ctl05$ctl02$ctl00$ctl00$ctl04$ctl00$ctl00$SelectResult>
    <OPTION title=Abington value=1>Abington</OPTION>
    <OPTION title=Acton value=2>Acton</OPTION>
    <OPTION title=Acushnet value=3>Acushnet</OPTION>


There’s a lot more to this simple little thing that you might have expected, eh? And I haven’t even gone into how the underlying script works. In fact, that’s so complicated that I’m going to leave it for another time.

The Inconsistency

But back to the whole point of this article, which is the inconsistency across language versions of SharePoint. The key is to be able to find the important piece parts of the control in the DOM with SPServices (in my case) and be sure that we are working with the right one if there are multiple multiselect columns in the form. To do this, I have a function in SPServices called dropdownCtl. Its little purpose in life is to find a “dropdown” and return an object reference to it in the DOM as well as its “Type”. The functions SPCascadeDropdowns, SPDisplayRelatedInfo, and SPLookupAddNew in SPServices all use the dropdownCtl function to find the right elements in the DOM to work with.

One other tricky part is that the are three types of “dropdowns” we can have in the form. (I’m using “dropdowns” in quotes because it’s a little bit of a stretch to call the multiselect control a dropdown.) Each type has different representations in the DOM elements, so dropdownCtl needs to find the right element and also decide which type of element it is.

The first two types are what you usually would think about as dropdowns, and they are easier to find in the DOM. They are either a “simple SELECT,” which is rendered if there are fewer than 20 options for the column, or a “complex SELECT,” which SharePoint uses if there are 20 or more options. The “complex SELECT” is actually a hybrid INPUT/SELECT with some script to drive it.

In the case of a “multiselect dropdown,” it’s a little trickier. The best way to find the various elements in the page for a “multiselect dropdown” is to look for the SELECTs’ titles. This is where the translation differences come into play.

It’s understandable (perhaps) that the English titles should be translated into the other languages. What doesn’t make sense is that the format of those translations is quite different. Let’s look at what the City column’s right box would have as its title in three different languages:

English City selected values
Russian Выбранных значений: City
(this is for the possible values, but the point is the same)
German Ausgewählte Werte für “City”

As you can see, the pattern of the text varies, not just the words themselves. I don’t speak Russian or German, but it’s hard to imagine that it’s necessary to change the construct from ‘City selected values’ to ‘Selected values: City’ or ‘Selected values for “City”‘ in order to reflect some sort of nationalistic thinking.

In my code, I don’t want to care about what language is being used; I just want to be able to find the right title. By using different patterns, SharePoint makes this more difficult than it should be.

The Solution

Because of the differences between the titles in the different language versions of SharePoint, in my dropdownCtl function I have to have these three conditions:

// Multi-select: This will find the multi-select column control in English and most other languages sites where the Title looks like 'Column Name possible values'
} else if ((this.Obj = $("select[ID$='SelectCandidate'][Title^='" + colName + " ']")).html() != null) {
  this.Type = "M";
  // Multi-select: This will find the multi-select column control on a Russian site (and perhaps others) where the Title looks like 'Выбранных значений: Column Name'
} else if ((this.Obj = $("select[ID$='SelectCandidate'][Title$=': " + colName + "']")).html() != null) {
  this.Type = "M";
  // Multi-select: This will find the multi-select column control on a German site (and perhaps others) where the Title looks like 'Mögliche Werte für &amp;quot;Tops&amp;quot;.'
} else if ((this.Obj = $("select[ID$='SelectCandidate'][Title$='\"" + colName + "\".']")).html() != null) {
  this.Type = "M";

Obviously, I can handle this in my code, but every time I hear from someone who uses a different language version of SharePoint and sees a bug, I need to revisit what the pattern of the text is in that language.

The Moral of the Story

The moral of the story is that seemingly tiny decisions can actually make more significant differences. Consider very carefully why you want to change the style of something like an ID or markup that you’re rendering in a control because there can be ramifications later. We all want to leave a little bit of our personal style in our code, but try not to do so at the expense of reusability, interoperability, or consistency.


Since I wrote this article back in 2010, I’ve made adjustments to handle additional languages. I’ve added Italian and I’ve recently been asked for a fix for Portuguese. Should you find another inconsistency, please let me know by posting in the SPServices Discussions on Codeplex.

Here’s what my DropdownCtl function looks like in version 2013.01:

// Find a dropdown (or multi-select) in the DOM. Returns the dropdown onject and its type:
// S = Simple (select);C = Compound (input + select hybrid);M = Multi-select (select hybrid)
function DropdownCtl(colName) {
  // Simple
  if ((this.Obj = $("select[Title='" + colName + "']")).length === 1) {
    this.Type = "S";
    // Compound
  } else if ((this.Obj = $("input[Title='" + colName + "']")).length === 1) {
    this.Type = "C";
    // Multi-select: This will find the multi-select column control in English and most other languages sites where the Title looks like 'Column Name possible values'
  } else if ((this.Obj = $("select[ID$='SelectCandidate'][Title^='" + colName + " ']")).length === 1) {
    this.Type = "M";
    // Multi-select: This will find the multi-select column control on a Russian site (and perhaps others) where the Title looks like 'Выбранных значений: Column Name'
  } else if ((this.Obj = $("select[ID$='SelectCandidate'][Title$=': " + colName + "']")).length === 1) {
    this.Type = "M";
    // Multi-select: This will find the multi-select column control on a German site (and perhaps others) where the Title looks like 'Mögliche Werte für &quot;Column name&quot;.'
  } else if ((this.Obj = $("select[ID$='SelectCandidate'][Title$='\"" + colName + "\".']")).length === 1) {
    this.Type = "M";
    // Multi-select: This will find the multi-select column control on a Italian site (and perhaps others) where the Title looks like "Valori possibili Column name"
  } else if ((this.Obj = $("select[ID$='SelectCandidate'][Title$=' " + colName + "']")).length === 1) {
    this.Type = "M";
  } else {
    this.Type = null;
} // End of function DropdownCtl

SPServices v0.7.1ALPHA13 Available for Testing

Faster and more furious, that’s what I always aim for.


I’ve been working hard on this next release of SPServices. I’ve been lucky to have some down time between projects to do it. Yes, I’m happy to have the gap so that I can do more and do it better; I’ve been able to make even more significant improvements because I’ve has the focused time. It’s a great feeling to look at my old code and know that I can do a lot better now. This version of SPServices is going to be leaner and faster than ever before. As I tweeted the other day:

Alpha13, which I just posted is, I think, a good one to think of as RC1. Before I get too busy again with client work, I want to get it out there for some of you to test. If you are an SPServices user and can do some testing, especially regression testing, I’d really appreciate it.

There’s also some new stuff that I’ve built into the last few alphas:

  • Better error messages for SPCascadeDropdowns, SPDisplayRelatedInfo, and SPFilterDropdown. If you have debug mode on and the listName is incorrect, you’ll get a clearer message.
  • Improvements to the new SPXmlToJson function. All of the documented options now work as advertised and I’ve optimized the code quite a bit.
  • SPCascadeDropdowns and SPDisplayRelatedInfo now have a matchOnId option. If matchOnId is set to true, the ID of the Lookup column is used rather than the text value. This can be handy where the same text value means different things, like the place-name of Springfield, which can be found in 34 of the US States. By default the behavior of the function remains the same, of course.
  • New operations: Lists.ApplyContentTypeToList, Lists.CreateContentType, Lists.DeleteContentType, Lists.GetListItemChanges, Lists.UndoCheckOut, Lists.UpdateContentType, SiteData.GetWeb
  • Numerous (and I do mean numerous) improvements for efficiency.

Enjoy, and let me know if you have a chance to try it out.

SPServices v0.7.1ALPHA8 Available for Testing

Yup, the alphas are coming fast and furious these days.

SPServicesI just posted a new alpha of SPServices v0.7.1. The most significant change in this alpha is the ability to have multiple child columns for a parent column in SPCascadeDropdowns. This was something I always intended it to do, but the last time I tried to work through it, probably well over a year ago, I wasn’t up to the challenge. This time I was, and I think that the function may also even be a teeny bit faster than it was in ALPHA7.

Here’s an example. In this simple list form, I’ve got a parent column called State and two child columns, one called City and the other called Second City.

By making two calls to SPCascadeDropdowns, both City and Second City are filtered based on the choice of State. I’ve also chosen to convert Second City from a “complex” dropdown to a “simple” dropdown by setting the simpleChild option to true.

  relationshipList: "Cities",
  relationshipListParentColumn: "State",
  relationshipListChildColumn: "Title",
  parentColumn: "State",
  childColumn: "City", // Child 1
  debug: true
  relationshipList: "Cities",
  relationshipListParentColumn: "State",
  relationshipListChildColumn: "Title",
  parentColumn: "State",
  childColumn: "Second City", // Child 2
  simpleChild: true,
  debug: true

Enjoy, and let me know if you have a chance to try it out.

SPServices v0.7.1ALPHA7 Available for Testing

I posted a new alpha of SPServices v0.7.1 today.logo250x150

Even though I just released v0.7.0 in early December, I’ve been working steadily to get some great new functionality and performance improvements into v0.7.1 as well as to fix some rather obscure bugs.

You can see the details of what is included in this alpha on the download page, but perhaps what will be of widest interest are some significant performance improvements to SPCascadeDropdowns and SPDisplayRelatedInfo. If you use those functions, I’d really appreciate you trying the alpha out and letting me know whether the improvements are noticeable to you. The initial setup time in the form won’t be faster, but the cascading in the page ought to be. (The better tuned your SharePoint farm and the more horsepower you have, the less improvement you are likely to see.)

I’ve also added a new function called SPXmlToJson. With it, I hope to offer a generic XML to JSON conversion utility. The first focus is on the XML returned by GetListItems, but I plan to expand upon it as people request additional capabilities. If you’re into playing with JSON, please take a look and give me your thoughts and suggestions. Be kind and remember that this is just an alpha.

Image via Wikipedia

The main reason for getting v0.7.0 (the prior release) out there was to release a version which was compatible with jQuery 1.7.x. As goeth jQuery, so goeth SPServices; the jQuery team doesn’t sit still for long, so I can’t really, either. In fact, jQuery 1.7.1 has already been out for a while and we can see 1.8 on the horizon. As part of the new jQuery releases, there are always some significant performance improvements as well as new capabilities. As with most software, there are also capabilities which are deprecated, which may by removed in the future.

Because of all of these changes to jQuery itself, along with my accompanying changes to SPServices, I would strongly encourage you to try to keep up with the releases as best you can. I know that this can be difficult, especially in large enterprise environments where the release cycles can be complex and time consuming.

Given the constraints that many people probably have when it comes to upgrading SPServices, I’m wondering what a good release cycle would be. There have already been over 2000 downloads of v0.7.0, yet I’m getting near the time when I might want to put v0.7.1 out there. What would work best for you? Fewer releases with more changes or more releases with fewer changes? There are many considerations to this, I know. If nothing else, the documentation can only represent one point in time (I’m loathe to try to keep historical versions; maintenance would be a nightmare). If you are using an older version of SPServices, like say v0.5.8, then the docs are pretty far off for you, as will be my blog posts and articles elsewhere. Let me know what you think!

Enhanced by Zemanta

Obscure (And Not So Obscure) Bugs with Complex Dropdowns in SharePoint Forms

As I’ve written in the past, there are several types of “dropdowns” in SharePoint forms. Briefly, there are:

  • “Simple” dropdowns – These are plain, old HTML selects; the type of dropdown you are most familiar with on the Web. SharePoint renders one of these when there are fewer than 20 options.

  • “Complex” dropdowns – SharePoint gives you these if there are 20 or more options. The interesting thing about this type of dropdown is that it is actually pretty ingenious, but very few people know why. When I ask in my presentations at various events who knows about the ingenious part, the percentage of people in the room who know about why they are ingenious is almost always less than 50% and usually far below. I’ll tell you how it works at the end of the post.

  • Multi-select dropdowns – Sure, these aren’t truly dropdowns, but they are what SharePoint displays when you when you offer the user a set of choices and want to allow them to select zero or more of those choices and you don’t choose checkboxes – sort of a dropdown.


The naming convention above is mine, one that I came up with when I was trying to understand the Document Object Model (DOM) which SharePoint renders so that I could write some of the cool functions in SPServices. The issues I am going to point out in this post occur with the “complex dropdown” only.

Issue One – The Wrong Selection

When a Lookup column’s list source has duplicate values and a validation error occurs elsewhere in the form, the first matching value is shown as selected, not the value which was selected if the selection was occurrence 2+. That’s a little hard to follow, so here is what I mean.

We can demonstrate this on a list form with a dropdown (Lookup) column and one other column which has validation of any type. In my example, there’s one column for State and another for City. Assume that there are two or more States with the name Alabama. (This isn’t a great example, but bear with me, as it will prove the point.) Also assume that there are 20+ States and that the City column is required.

When we select the second Alabama value and no City is selected, on submit there is a validation error because a City is required.


That’s all well and good, and what we would like to have happen:


However, the first occurrence of Alabama is now selected rather than the second, which we had selected:


This may be a weak example, but it still proves that there is a bug introduced by the complex dropdown control. If the person setting up the list for States knows enough about relational data, they won’t have multiple items in the list with the same Title. However, many users (and frankly, many IT people) are not well-versed in the nuances of building a good information architecture which follows the rules of relational data constructs. It’s reasonable to expect that SharePoint will record the correct value.

The bug is introduced because rather than saving and matching on the selected option’s value (which is the ID for the item in the Lookup list), the text of the selected option is used to match, therefore causing the error. I’ve had to introduce the same bug into SPServices so that I can mimic the out of the box functionality.

This bug is identical in SharePoint 2007 and 2010.

Issue Two – User Interface Bug with No Dialogs

This issue occurs only in SharePoint 2010. By default, list forms in 2010 are displayed in a dialog box. What this means is that rather than going to an entirely new page to display the form as happens in SharePoint 2007, the form is “popped up” over the current page, which is usually a list view.

When the form is shown in the dialog box, all is well and good, and the complex dropdown looks like this when you try to choose an option:


However, if you decide to turn off the dialogs (List Settings / Advanced Settings / Dialogs – way down at the bottom of the screen), there is a display issue where the available values are shifted about 155px to the right:


The dropdown otherwise functions just fine, but it sure doesn’t look right.

In my opinion, and based on conversations with my clients, the constant dialogs are an anathema in SharePoint 2010. They certainly make forms which have any complexity to them harder to fill out. I usually recommend turning the option for dialogs off for many forms. Unfortunately, it’s a manual, repetitive process.

The complex dropdown is truly a complicated beast. It’s made up of multiple HTML elements and JavaScript which allows it to function. Unfortunately, that markup and scripts doesn’t seem to have gone through a perfect Quality Assurance (QA) process.

Oh, and the ingenious part of the complex dropdown I promised you? When you start typing in the input element – yes, you can type in there! – the control filters the available values it shows. For example, if I type “sou” into the input element, I only see the “South Dakota” and “South Carolina” values in the dropdown.


This is great functionality, but since so few people know about it, especially real users of SharePoint, it serves little purpose other than to confuse everyone!