Dependent Drop Downs, Cascading Drop Downs, Filtered Drop Downs. Whatever you want to call them, this is where you have a secondary drop down list filtered based on the choice from the primary drop down list. For example: select a country and you get another drop down list populated with the cities in that country.
This functionality doesn’t seem to be there in WSS 3.0 and/or MOSS 2007. Perhaps I am missing something? (It wouldn’t be the first time) But this seems to be fundamental functionality. Here is some more detail on the scenario:
Country List: I just want a basic drop down list of countries:
City List: I want to filter the cities based on the selected country:
I want a cascading or filtered drop down like so (select Australia, and get a list of Austrlian cities):
Select Germany and get a list of German cities:
Anyway, I couldn’t find a way to do this out of the box, so…I decided to create my own custom field controls to overcome the problem.
I found a couple of useful articles on writing custom field controls. This article describes how to create a custom drop down list user control along with a custom property page:
http://www.kcdholdings.com/blog/?p=56
I used a lot of code from this example, which has a couple of interesting points.First of all it shows how to create a custom Choice field that can be populated from any list on any site on the web farm (not just the current site). It also has an example of a way to get around the problem of saving custom properties of field controls. For some reason this is not as easy as it should be. I think this will be fixed in SP1. This article describes this problem:
http://www.sharepointblogs.com/ aaronrh/archive/2007/05.aspx
Instead of using a delimited string, I used a class to temporarily store the property values. Here is what my property pages look like for the Parent and Child drop down lists:
Anyway, after learning how to overcome the challenges of field controls in general, it was time to move on to the bigger problem of finding a way to create cascading drop downs. I figured there was hope in the “cross list query” or “caml query”:
http://msdn2.microsoft.com/en- us/library/ms467521.aspx
For example, if I want to filter a list of cities based on a country field in that list:
string caml = @“<WHERE>
<EQ>
<FIELDREF Name=”{0}” /><VALUE Type=”Text”>{1}</VALUE>
</EQ></WHERE>;
SPQuery query = new SPQuery();
query.Query = string.Format(caml, “Country”, “Australia”);
SPListItemCollection results = list.GetItems(query);
this.ChildDropDownList.DataSource = results.GetDataTable();
this.ChildDropDownList.DataTextField = “City”;
this.ChildDropDownList.DataValueField = “City”;
this.ChildDropDownList.DataBind();
So I have a parent drop down list that has a SelectedIndexChanged event, that I use to call a method in the child control that binds to the results of the above query.
void ParentDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
ChildDropDownListFieldControl child = (ChildDropDownListFieldControl)
FindControlRecursive(this.Page, “ChildDropDownList”).Parent.Parent;
child.SetDataSource(ParentDropDownList.SelectedValue);
}
I played around with a lot of different ways to locate the Child drop down list on the page. This is the only one I got to work. (There has to be a better way?)
Anyway, I would appreciate any feedback on any better ways to do this. Here is the source code; I also have a solution file that you can use to install the controls. Just edit the install.bat and point it to the WSS or MOSS site you want to install it on.