Reinvent the wheel, rewrite cascading dropdown controls
My colleague is a cycling fanatic. She spent over 1,000 dollars on a bike, moreover, she paid a stack of money for a hand-made back wheel for her bike. This is her:

What? A hand-made wheel? A classic case of reinventing the wheel.
I digressed, but, not entirely. You will see.
ASP .net ajax extenders carry the promise of a plug-and-play. You plug your usb drive, there you get an extra drive. In a lot of straightforward, predicated scenarios, this is the case.
For example, the quite popular cascadingdropdown extender. Plug it in onto a server-side dropdownlist, every selectIndexChanged event of a parent dropdown would trigger the domino effect of cascadingly populate the next dropdownlist in line. True. This works with unambiguous scenarios where dependancy is one to one, for example, state -> city -> zipcode.
However, what if there is multiple dependancies where a fellow dropdown's values are decided not just by its immediate parent, but also the grandparent? For example, both the age factor and gender factor will decide the possible interests one may have. What if you need to populate your date dropdownlist depending on both of the year given and month choosen. This is the scenario where a DNS user asked about.
Thus, we need to go beyond the formula provided by cascadingdropdown extender, we need to reinvent the wheel. This brings to the real purpose and essence of ASP .net AJAX, the ability to call web service smoothly and gracefully from client side JavaScript.
The web service
The following is a silly web service to create some fake dates, please note that it is adorned with the ScriptService attribute that makes it available to JavaScript clients as well
using System;
using System.Collections;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
/// <summary>
/// Summary description for DateTest
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class DateTest : System.Web.Services.WebService {
[WebMethod]
public int[] GetYears()
{
int[] years = new int[10];
for (int i = 0; i < years.Length; i++)
years
= 2000 + i;
return years;
}
[WebMethod]
public string[] GetMonths(string value)
{
string[] month1 = new string[] { "Jan", "Feb", "Mar", "April" };
string[] month2 = new string[] { "May", "June", "July", "Aug" };
string[] month3 = new string[] { "Sep", "Oct", "Nov", "Dec" };
if (int.Parse(value) < 2006)
return month1;
if (int.Parse(value) > 2006 && int.Parse(value) < 2008)
return month2;
return month3;
}
[WebMethod]
public int[] GetDays(string value1, string value2)
{
int[] days = new int[10];
int i;
if (int.Parse(value1) < 2006 && int.Parse(value2) < 2)
{
for (i = 0; i < 10; i++)
days
= i;
}
else if (int.Parse(value1) < 2006 && int.Parse(value2) > 2)
{
for (i = 0; i < 10; i++)
days
= i + 10;
}
else if (int.Parse(value1) > 2006 && int.Parse(value2) < 2)
{
for (i = 0; i < 10; i++)
days
= i + 20;
}
else
for (i = 0; i < 10; i++)
days
= i + 15;
return days;
}
}
To call the web service from JavaScript
First thing, you have drag and drop the ubiqutous ScriptManager to your .aspx page to oversee all AJAX operations:
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="DateTest.asmx" />
</Services>
</asp:ScriptManager>
Get the cascading dropdown to work:
function page_load(sender, e){
ddlYear = $get("ddlYear");
ddlMonth = $get("ddlMonth");
ddlDay = $get("ddlDay");
DateTest.GetYears(onGetYears);
$addHandler(ddlYear, "change", year_onchange);
$addHandler(ddlMonth, "change", month_onchange);
}
function page_unload(sender, e){
$removeHandler(ddlYear, "change", year_onchange);
$removeHandler(ddlMonth, "change", month_onchange);
}
function year_onchange(sender, e){
var y = ddlYear.value;
DateTest.GetMonths(y,onGetMonths);
}
function month_onchange(sender, e){
var y = ddlYear.value;
var m = ddlMonth.value;
// alert(y + " " + m);
DateTest.GetDays(y,m,onGetDays);
}
function onGetYears(result){
for(var i = 0; i<result.length; i++)
{AddToOptionList(ddlYear, result
,result
);
}
}
function onGetMonths(result){
ClearOptions(ddlMonth);
for(var i = 0; i<result.length; i++)
{AddToOptionList(ddlMonth, i,result
);
}
}
function onGetDays(result){
ClearOptions(ddlDay);
for(var i = 0; i<result.length; i++)
AddToOptionList(ddlDay,i,result
);
}
function AddToOptionList(OptionList, OptionValue, OptionText) {
// Add option to the bottom of the list
OptionList[OptionList.length] = new Option(OptionText, OptionValue);
}
function ClearOptions(OptionList) {
// Always clear an option list from the last entry to the first
for (x = OptionList.length; x >= 0; x--) {
OptionList[x] = null;
}
}
Conclusion:
So i have completely ditched the server-centric programming model and the singleton-dependancy cascadingdropdown extenders, and wrote a set of cascading html select controls. The secret ingradient: using ASP .net AJAX extensions to call a web service.
Note:
you know that all array notation with i in the bracket "["i"]" is automatically turned into a shiny yeallow light bulb! The life of icons.
