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.

image

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.

image

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

image

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

image

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:

image

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:

image

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.

image

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!

Two Types of SharePoint Forms Dropdowns

I think I’ve typed bits and pieces of this post to people a few hundred times. Why I have never thought to make it a post is beyond me!  SharePoint renders dropdowns in forms two different ways, depending on how many options there are in the column.

If there are fewer than 20 options, then SharePoint gives you what I call a “simple” dropdown.  It’s just a plain old select.

image

If there are 20 or more options, then SharePoint gives you what I call a “complex” dropdown. It’s made up of an input element and a hidden select with a bunch of script in core.js that ties it all together to make it work.

image

Can you see the difference? It’s not all that obvious at first glance, but the way you can tell easily is to look at the little dropdown icons.

image

See how the first icon has a darker triangle?  And the second has a little grey border?

I had to figure this out and get *very* familiar with it when I was building my SPCascadeDropdowns function in SPServices.  If you are trying to do anything to manipulate dropdowns in the DOM, you’ll need to understand them, too.

Even more annoying to users, though, is that they behave differently.

The simple type of dropdown behaves normally.  You can click on the icon or anywhere in the text area, the values drop down, you can select one, and the dropdown closes up immediately.

With a complex dropdown, the behavior is different.  If you click in the text area (actually the input element), nothing happens. You need to click on the icon, which then drops down the values (there’s a click event on that little image (/_layouts/images/dropdown.gif). Then you can click on a value, but the dropdown will not close up!  You have to either double click the value or click elsewhere (to remove focus) for the dropdown to close.

In my experience, the behavior difference is what drives end users batty. Most of them don’t even notice the visual difference, but the double click things is really annoying.  It’s one of the tiny little things that make people wonder what’s “wrong” with SharePoint.  Sure, try to explain the underlying functionality differences and watch the blank stares.  You won’t win that one!

Finally, the value storage and capture mechanisms are totally different as well.  Here is the DOM snippet for a simple dropdown:

<SPAN dir=none lpcachedvisval="1" lpcachedvistime="1274306928"><SELECT id=ctl00_m_g_01a3a856_7297_48e8_b963_10c9826b4b82_ctl00_ctl04_ctl01_ctl00_ctl00_ctl04_ctl00_DropDownChoice-RadioText title="Lead Source" name=ctl00$m$g_01a3a856_7297_48e8_b963_10c9826b4b82$ctl00$ctl04$ctl01$ctl00$ctl00$ctl04$ctl00$DropDownChoice lpcachedvisval="1" lpcachedvistime="1274306928"> <OPTION value="Newspaper Advertising">Newspaper Advertising</OPTION> <OPTION selected value="Web Site">Web Site</OPTION> <OPTION value="Personal Referral">Personal Referral</OPTION></SELECT><BR></SPAN>

and for a complex dropdown:

<SPAN dir=none lpcachedvisval="1" lpcachedvistime="1274306973"><SPAN style="VERTICAL-ALIGN: middle" lpcachedvisval="1" lpcachedvistime="1274306973"><INPUT onkeydown=HandleKey() id=ctl00_m_g_01a3a856_7297_48e8_b963_10c9826b4b82_ctl00_ctl04_ctl04_ctl00_ctl00_ctl04_ctl00_ctl01-lookuptypeintextbox title=State onfocusout=HandleLoseFocus() onkeypress=HandleChar() onchange=HandleChange() value="Rhode Island" name=ctl00$m$g_01a3a856_7297_48e8_b963_10c9826b4b82$ctl00$ctl04$ctl04$ctl00$ctl00$ctl04$ctl00$ctl01 choices="Alabama|23|Alaska|20|Arizona|8|California|3|Colorado|4|Florida|5|Georgia|6|Idaho|13|Illinois|21|Indiana|17|Massachusetts|1|Missouri|22|Nevada|7|New Jersey|16|New York|15|Ohio|10|Oregon|12|Pennsylvania|14|Rhode Island|2|Texas|18|Washington|11|Wyoming|9" match="" optHid="SPState_Hiddenctl00$m$g_01a3a856_7297_48e8_b963_10c9826b4b82$ctl00$ctl04$ctl04$ctl00$ctl00$ctl04$ctl00" opt="_Select" lpcachedvisval="1" lpcachedvistime="1274306973"><IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; VERTICAL-ALIGN: middle; BORDER-LEFT-WIDTH: 0px" onclick="ShowDropdown('ctl00_m_g_01a3a856_7297_48e8_b963_10c9826b4b82_ctl00_ctl04_ctl04_ctl00_ctl00_ctl04_ctl00_ctl01');" alt="Display lookup values" src="/_layouts/images/dropdown.gif"></SPAN><BR></SPAN>

See? ;+)

Firing an Event When a User Selects a Value from a Data View Web Part Dropdown

I was skimming my old postings, and I realized that in a previous post, I had said that I would post about firing an event when a user selects a value from a DVWP dropdown.  Better late than never, I guess.

When you create a dropdown type of DVWP through the UI in SharePoint Designer, the dropdown is created just fine, but there is absolutely nothing there to make that dropdown actually *do* anything.  Helpful, but not much.  Here’s how you can make it worth something.

In this example, my goal was to pass the chosen value to another page through the query string (There are other ways to do this, but for this client, there was auditing software that made having the value in the URL of use.) so that I could display the set of items that were created during a specific archive period.  (I had a calculated column that gave the archive period based on the published date — see this post on how that works.)

  • Add a DVWP to the page
  • Drop the column you want to see onto it
  • Change layout and choose the second from the bottom option — Dropdown menu of titles

To get at the query string variable ArchivePeriod (seen in the code below referred to as $ArchivePeriod) you go to the DVWP ‘Common Dataview Tasks’ (click on the little > button to the right on the DVWP), and set up a Parameter as seen in the screen snippet below.  If you search the code for the page for ArchivePeriod after doing this, you can see the effect of your actions.  You can, in fact, add the variable directly into code, as you see! (There are two lines for ArchivePeriod now.)

Data View Parameters

The key portions of the code that SharePoint creates when you add this DVWP to the page as in the three steps above are as follows:

<xsl:template name="dvt_1">
...
<select name="ID" size="1">
<option selected="true" value="0">Choose One...</option>
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows" />
<xsl:with-param name="FirstRow" select="1" />
<xsl:with-param name="LastRow" select="$dvt_RowCount" />
</xsl:call-template>
</select>

and

<xsl:template name="dvt_1.rowview">
<option>
<xsl:value-of select="@Archive_x0020_Period" />
</option>
</xsl:template>

While Designer has created a nice dropdown for you, nothing will happen if you make a selection; that work is left to you.  Here are the changes that I made; I’ve explained the changes below.

<xsl:template name="dvt_1">
...
<select size="1" onchange="HandleFilterSelection('default.aspx', 'PageFilterArchive.aspx', 'ArchivePeriod', this.options[selectedIndex].value)">
<xsl:choose>
<xsl:when test="not(string-length($ArchivePeriod))" >
<option value="0">Choose Dates</option>
</xsl:when>
<xsl:otherwise>
<option value="*">All Dates</option>
</xsl:otherwise>
</xsl:choose>
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows" />
</xsl:call-template>
</select>

<xsl:template name="dvt_1.rowview">
<xsl:variable name="NewGroup" select="ddwrt:NameChanged(string(@Archive_x0020_Period), 0)" />
<xsl:if test="string-length($NewGroup)">
    <option>
<xsl:if test="$ArchivePeriod = @Archive_x0020_Period">
<xsl:attribute name="selected">
<xsl:value-of select="selected" />
</xsl:attribute>
</xsl:if>
<xsl:attribute name="value">
<xsl:value-of select="@Archive_x0020_Period" />
</xsl:attribute>
<xsl:value-of select="@Archive_x0020_Period" />
</option>
</xsl:if>
</xsl:template>

function HandleFilterSelection(defaultpath, filterpath, parameter, selection)
{
if(selection == "*")
{
document.location.href = defaultpath;
}
else
{
document.location.href = filterpath + "?" + parameter + "=" + selection;
}
}
  • Line 3: Adding the onchange event allows you to provide an action if the value in the dropdown changes.  I decided to handle this in an externally stored Javascript function called HandleFilterSelection so that I could reuse it easily.
  • Lines 4-11: This xsl:choose lets me alter the prompt based on whether there is currently a filter in place or not.
  • Lines 18-19: This code lets me test to eliminate duplicate values.  This works because I have the list items sorted in descending order by Publish Date.
  • Lines 22-24: If the value is the currently selected value (i.e., it is driving the current filter on the page), this code lets me set it as the selection in the dropdown.
  • Lines 26-28: Unless you specifically set the value that will be returned for the selection, it’s an unpredictable number.  By setting it to the actual text of the selection, we can ensure the it is both recognizable and unique.

UPDATE 2009-05-01 — As a response to Patrick’s question below (It’s hard to include code in a comment.):

In my example, the HandleFilterSelection JavaScript was stored externally from the page because I used it in many places.  (I usually create a Document Library in the root site of the Site Collection called JavaScript to store .js files. I then include them in the pages where I want to use them by adding a <script src=”blah.js”> into the page.)

You can have the onchange event for the select do anything you want.  For example, I often just call the same page with a Query String parameter, like in the code snippet below:

<select name="SelectFluid" size="1">
<xsl:attribute name="onchange">
document.location =
&apos;<xsl:value-of select="$URL"/>&apos; +
&apos;?F=&apos; + this.options[selectedIndex].value;
</xsl:attribute>

To have this work, declare a parameter in the ParameterBindings section for the URL server variable (see my post entitled Data View Web Part Parameters Based on Server Variables for more on using IIS server variables):

<ParameterBinding Name="URL" Location="ServerVariable(URL)" DefaultValue=""/>

and then declare the parameter at the start of your XSL:

<xsl:stylesheet [...]>
<xsl:output method="html" indent="no"/>
<xsl:param name="URL"/>