Custom Multi-select Control
Tuesday, March 25, 2008 at 6:53PM |
Kevin Rohrbaugh The current project I'm on has several multi-select meta-data items where users select one or more of what can be a long list of options during an approval process. We started off with a user interface that simply offered them an ASP.NET ListBox (more commonly known as an HTML Select element) and allowed for multiple selections using the Control key. This solution, while functional, makes it difficult to see all the selections in a list where the available options are larger than the list-box itself. Due to this, the users requested a multi-select control where selected items appear in one list, and options in another. Here's how the final control ended up looking, where the left list has the available options and the right the selected ones:

We've all seen similar controls on various pages, so this isn't a revolutionary idea or anything, but I thought I'd post some quick notes I discovered along the way, in case others are building anything similar. I should also note that I implemented this as a User Web Control (ASCX) since Server Controls continue being more of a pain than their worth in my opinion.
First off, one issue has to deal with what values are sent back to the server during a form post. I kept referencing the ListBox.Items collection in the code-behind but it always just had the items that were sent to the client originally. It turns out that HTML select elements only send back the selected values of the list, not the entire item set. Since the control is changing the items of the element using client-side JavaScript, and using what select element the items were within as the means of selection, the server had no visibility to what the user had done. In order to work around this, I decided to use hidden form fields that store delimited values of the two select elements (options and selections) which are then parsed during the Page_Load event of the ASCX and replace the Items collection of the two ListBox controls. There are other ways to do the same thing, but the critical component is that only items selected in a select element are sent back to the server, so any changes made to the list items in JavaScript are invisible without some sort of work-around.
The second issue had to deal with some oddness in IE's JS interpreter when it came to sorting the options. I basically had a sort method that looked like this (I'm aware that this method is lame, but it was late, I was well into get it to work territory):
_itemSorter: function(a, b)
{
/// <summary>Sorts the selection list by display text</summary>
/// <param name="a">First item to compare</param>
/// <param name="b">Second item to compare</param>
var c = a.text;
var d = b.text;
if (c < d )
{
return -1;
}
else if (c > d)
{
return 1;
}
else
{
return 0;
}
}
Which worked fine in FireFox, but threw a "Number expected" error in IE (both 6 and 7). I'm not exactly sure what causes this error, but I fixed it by using the following code instead:
_itemSorter: function(a, b)
{
/// <summary>Sorts the selection list by display text</summary>
/// <param name="a">First item to compare</param>
/// <param name="b">Second item to compare</param>
return (a.text < b.text ? -1 : ((a.text > b.text) ? 1 : 0));
}
This function is then used to sort the arrays that work as the backing store for the two select elements:
_sortArray: function(array)
{
/// <summary>Sorts the array based on display text</summary>
/// <param name="array">Array to sort</param>
array.sort(this._itemSorter);
}
When it was all said and done, the control works well, and while it's far from robust and full-featured, it gets the job done for what we need in this particular project. Hopefully these notes help somebody else out there avoid some of these pitfalls should they need to build something similar.
ASP.NET 
Reader Comments