A collection of learnings and opinions.

Thursday, August 2, 2007

DropDownList with a blank item on top

The DropDownList (DDL) is a nice little databindable control in ASP.Net. The easiest way to use it is to databind it to some value from your database and let the user select.

The problem with straight on databinding is that the first item in the DDL will be the first item in the databound collection (naturally), thus making choosing that item "a little too easy" and "a little too hard". When the user wants to select the top item you might be in for problems, as that selection won't fire off a SelectedIndexChanged -event, which is what you'd normally listen for.

There are ways around this - I've seen several suggestions. None of these are even starters in my opinion:
  • Don't handle changes in the DDL, read from it on some other event (typically a button)
    • This makes it very hard to create responsive UIs, as your user will always have to keep clicking buttons
  • Set whatever you want to happen on changes in the DDL as if the first choice was already chosen (pre-choose for the user)
    • Badness - especially in a stateless media like the web - your user may never correct your initial (possibly wrong) assumption
  • Add an empty record in the databound object (typically your database)
    • Perhaps the worst idea I've seen. The database should not contain filler like this. It's a bit better if you're working with some transient object - but still it's a hack. We don't like hacks.
The way to fix this problem is really not very hard. What you want is an empty item on the top of the list that the user will not expect to work, with a known value you can check for in your SelectedIndexChanged handler.

To do this add a ListItem to the DDL in the page/control's definition with your sentinel value and an empty string as the Text property. Normally this item would disappear on databinding, but wait: set the AppendDataBoundItems property on the DDL to True, and your empty initial value will survive!

Two things to beware: Make sure you check for your sentinel value in the handler, and remember to clear all but the initial item of the DDL's ItemListCollection if you're databinding that control again later (unless you want to keep appending).

Here's your illustrative code:
A standard DDL:

<asp:DropDownList id="ddBasic" runat="server" autopostback="True">
<!-- Selecting the top item will not fire an event (it will be pre-selected) -->

A DDL with the empty top-item:

<asp:DropDownList id="ddWithEmptyTop" runat="server" autopostback="True" appenddatabounditems="True">
<asp:ListItem value="-1" text=""> </asp:ListItem>

Technorati Tags: , , ,


Anonymous said...

Hello. This post is likeable, and your blog is very interesting, congratulations :-). I will add in my blogroll =). If possible gives a last there on my blog, it is about the Servidor, I hope you enjoy. The address is http://servidor-brasil.blogspot.com. A hug.

Shehryar Hussain said...

AWESOMe!! i needed that..

Shehryar Hussain said...

na didn't work for me.. now whenever i select another selection it keeps adding up on the other.. i guess ill try the blank database now..

Tomas said...

I hope you didn't go with the blank in the database! What you have to do is handle when to blank the list of items in the DropdDownList. Make sure you include a ddl.Items.Clear() before you re-populate the list.

Seriously - blank items in the database just to show them in a particular way in a particular GUI is not the way to go!

Shehryar said...
This comment has been removed by the author.
Shehryar Hussain said...

Thanks great just in time! Ill try that now.!

Thomas Radioyes said...

Thanks! it works just fine.

Anonymous said...

Works great. Thank you.

SRK said...
This comment has been removed by the author.
SRK said...

Hey your solution is awesome. But I have multiple dropdown lists in a single page, where when one ddl is selected, the second ddl is updated accordingly from the 1st ddl selection and so on. your procedure is fine for the first dropdown list.then i select an item in 2nd one, then if i change item in 1st ddl, the selected item in 2nd ddl is being displayed again for the new 2nd ddl. What is the solution for this and what were you talking about ddl.items.clear(). Where do i use this??


Tomas said...

I may have misunderstood your problem, but to me it sounds like you have two DropDownLists: A and B, with selection of an item in A one causing population of B. When your user changes his/her selection in A you still get the items in B that were populated after the first selection in A.

If this is the case (and made any sense) you're missing the B.Items.Clear() in the A.SelectedIndexChanged_Handler.

Tomas said...

Made an example of two DropDownLists with blanks on top and one populating the other.
The aspx file is here: http://pastebin.com/fb208399
And the Code-behind (in C# this time) is here: http://pastebin.com/f71942fed

SRK said...

Hey Tomas, thanks for the effort. I played with it a little after my post and i got it to work the way i wanted it to.

But i had another question, i did add the items.clear and item.add for this and the item.add is empty which is the first entry of the dll. But when i change from one item to another item in the dll, i still see the empty space in the list and when i click on it, it executes a script that i wrote.

i wanted to know if there is anyway that i can remove this empty space once a selection has been made in the dll. i hope i am clear and thanks for this post, it really helped :)

Lars said...

A simple yet elegant solution that works perfectly. All from reading the API.

And here I was fumbling around with JQuery.

Good work, Tomas.

Jason said...

Awesome, thanks!