sharing about .NET and technology RSS 2.0
 Thursday, January 25, 2007

In some enterprise applications you need to show geographical data such as countries and postcodes. Most of the time you need it for a registration page, where the user need to fill in the country and postcode/area.

Geonames is a free geographical database that contains over 8 million geographical names and it can be accessed through a number of webservices. For example the url http://ws.geonames.org/countryInfo? gives an xml with all countries, whereas the following request http://ws.geonames.org/postalCodeSearch?placename=be gives us all postcodes for a particular country (e.g. Belgium).

Most likely you need two dropdown lists, one for countries and one for postcodes, where the postcode dropdown is dependent from the country dropdown list. This is a very good example to introduce AJAX by using the CascadingDropdown that is included in ASP.NET AJAX.

To implement this functionality we need to implement two methods on a webservice, namely GetCountries and GetPostalCodesByCountry. The GetCountries simply returns all countries sorted by name and looks like this:

GeonamesService.asmx.cs - Copy Code
[WebMethod] public CascadingDropDownNameValue[] GetCountries() { List<CascadingDropDownNameValue> list = new List<CascadingDropDownNameValue>(); CountryItemCollection countries = IStaySharp.Geonames.GeonamesService.GetAllCountries(); for (int i = 0; i < countries.Countries.Length; i++) { list.Add(new CascadingDropDownNameValue( countries.Countries[i].CountryName, countries.Countries[i].CountryCode)); } list.Sort(CompareCascadingDropDownNameValueByName); return list.ToArray(); }

Note that the list need to be converted to an array of CascadingDropDownNameValue objects. Note that we also sort the list by implementing a delegate named CompareCascadingDropDownNameValueByName.

GeonamesService.asmx.cs - Copy Code
private static int CompareCascadingDropDownNameValueByName(CascadingDropDownNameValue x, CascadingDropDownNameValue y) { if (x == null && y == null) return 0; else if (x == null && y != null) return -1; else if (x != null && y == null) return 1; else return x.name.CompareTo(y.name); }

The other webservice method, called GetPostalCodesByCountry, need to retrieve all postcodes for a particular country. The signature of the method is very strict. The parameter names must be named 'knownCategoryValues' and 'category', otherwise it will fail!

GeonamesService.asmx.cs - Copy Code
[WebMethod] public CascadingDropDownNameValue[] GetPostalCodesByCountry(string knownCategoryValues, string category) { List<CascadingDropDownNameValue> list = new List<CascadingDropDownNameValue>(); StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues); if (kv.ContainsKey("Country")) { string countryName = kv["Country"]; PostalCodeItemCollection postalCodes = IStaySharp.Geonames.GeonamesService.GetPostalCodes(countryName); for (int i = 0; i < postalCodes.PostalCodes.Length; i++) { list.Add(new CascadingDropDownNameValue( string.Format("{0} ({1})", postalCodes.PostalCodes[i].PostalCode, postalCodes.PostalCodes[i].Name), postalCodes.PostalCodes[i].PostalCode)); } } list.Sort(CompareCascadingDropDownNameValueByName); return list.ToArray(); }

In order to complete the webservice, the attribute ScriptService (line 3) need to be included so that a client javascript proxy can be generated. You can test this by calling your webservice like this http://localhost:9999/GeonamesService.asmx/js.

GeonamesService.asmx.cs - Copy Code
1 [WebService(Namespace = "http://tempuri.org/")] 2 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 3 [System.Web.Script.Services.ScriptService()] 4 public class GeonamesService : System.Web.Services.WebService 5 { 6 ... 7 }

Finally we only need to add two CascadingDropDown controls on our aspx page with the following settings:

Default.aspx - Copy Code
<asp:ScriptManager ID="scriptManager" runat="server" /> <asp:DropDownList ID="countriesDropDown" runat="server"/> <ajaxToolkit:CascadingDropDown ID="countriesCascadingDropDown" TargetControlID="countriesDropDown" Category="Country" PromptText="Please select a country" LoadingText="[Loading countries...]" ServicePath="/GeonamesService.asmx" ServiceMethod="GetCountries" runat="server"/> <br/><br/> <asp:DropDownList ID="postalCodesDropDown" runat="server"/> <ajaxToolkit:CascadingDropDown ID="postalCodesCascadingDropDown" TargetControlID="postalCodesDropDown" Category="PostalCode" PromptText="Please select postalcode" LoadingText="[Loading postalcodes...]" ServicePath="GeonamesService.asmx" ServiceMethod="GetPostalCodesByCountry" ParentControlID="countriesDropDown" runat="server"/>

The source code can be downloaded here: IStaySharp.AJAXSample.rar (332,56 KB)

Thursday, January 25, 2007 2:13:28 AM (Romance Standard Time, UTC+01:00)  #    Comments [2] -
 | 
Tuesday, August 05, 2008 2:11:26 AM (Romance Standard Time, UTC+01:00)
I have the following:

function
Register_SelectedIndexChangedDaysInMonth()

{


var monthDropdown = $get('<%=ddlMonth.ClientID%>'
);


var yearDropdown = $get('<%=ddlYear.ClientID%>'
);

alert (

"HELLO WORLD"
+ yearDropdown.value);


return 32 - new
Date(monthDropdown.value, yearDropdown.value, 32).getDate();



How can I build an array for the dropdownlist ddlDay.

function Register_pageLoad(sender, args)
{
$find("myCDEDay").add_selectionChanged(Register_SelectedIndexChangedDaysInMonth);
}

<ajaxToolkit:CascadingDropDown ID="cddMonth" runat="server" Category="Month"
TargetControlId="ddlMonth" SelectedValue=""
LoadingText="[Loading Months...]"
ServicePath="../LocationService.asmx"
ServiceMethod="GetMonthList" Enabled="True" />

<ajaxToolkit:CascadingDropDown ID="cddYear" runat="server" Category="Year"
TargetControlId="ddlYear" SelectedValue=""
LoadingText="[Loading Year...]"
ServicePath="../LocationService.asmx"
ServiceMethod="GetYearList" Enabled="True" />

<ajaxToolkit:CascadingDropDown ID="cddDay" runat="server" Category="Day"
TargetControlId="ddlDay" BehaviorID="myCDEDay" SelectedValue=""
ParentControlID="ddlMonth"
LoadingText="[Loading Day...]"
ServicePath="../LocationService.asmx"
ServiceMethod="GetDayList" Enabled="True" />

I need to include in the cddDay two ParentControl ID in order to calculate the following:
[WebMethod(Description = "Populate a days list for a specific month and year.")]
[System.Web.Script.Services.ScriptMethod]
public AjaxControlToolkit.CascadingDropDownNameValue[] GetDayList(string knownCategoryValues, string category)
{


StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);
List<CascadingDropDownNameValue> dayList = new List<CascadingDropDownNameValue>();

int year;
if (!kv.ContainsKey("Year") ||
!Int32.TryParse(kv["Year"], out year))
{
return null;
}

int month;
if (!kv.ContainsKey("month") ||
!Int32.TryParse(kv["month"], out month))
{
return null;
}

int NumberOfDays = DateTime.DaysInMonth(year, month);

for (int day = 1; day <= NumberOfDays; day++)
{
dayList.Add(new CascadingDropDownNameValue(day.ToString(), day.ToString()));
}



return dayList.ToArray();
}
/////////////////////////////////////////////////////////////////////////////////////////
matt
Tuesday, September 23, 2008 4:27:42 AM (Romance Standard Time, UTC+01:00)
Hi,
I am trying to use your code, firstly thanks for putting it up for everyone.
this bit of code the sort operation which I am interested in:

I have convert this code to VB and it obviously will asks for the parameters for this function(CompareCascadingDropDownNameValueByName), then am not sure how it will work:

list.Sort(CompareCascadingDropDownNameValueByName);
return list.ToArray();

THanks.

Cheers,
Sandeep Kapil.
Sandeep Kapil
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):

Navigation
Archive
<November 2008>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008
Christoph De Baene
Sign In
Statistics
Total Posts: 151
This Year: 22
This Month: 1
This Week: 0
Comments: 147
All Content © 2008, Christoph De Baene
DasBlog theme 'Business' created by Christoph De Baene (delarou)