neo neo - 5 months ago 25
jQuery Question

Cascading drop down list (SubLocality) not working in asp.net mvc

I have three dropdown List.The First action method for City drop down is as---

public ActionResult Create()
{
List<SelectListItem> li = new List<SelectListItem>();
li.Add(new SelectListItem { Text = "Select your City", Value = "----" });
li.Add(new SelectListItem { Text = "Faridabaad", Value = "Faridabaad" });
li.Add(new SelectListItem { Text = "Greater Noida", Value = "Greater Noida" });
li.Add(new SelectListItem { Text = "Gurgaon", Value = "Gurgaon" });
li.Add(new SelectListItem { Text = "Noida", Value = "Noida" });
li.Add(new SelectListItem { Text = "New Delhi", Value = "New Delhi" });
ViewData["City"] = li;
return View();
}


then i have action method for my Locality drop down list which changes as we change city name like this------

public JsonResult LoadLocalities(string id)
{
List<SelectListItem> localities = new List<SelectListItem>();
switch(id)
{
case"New Delhi":
localities.Add(new SelectListItem { Text = "Select your locality", Value = "0" });
localities.Add(new SelectListItem{ Text ="East Delhi", Value = "1" });
localities.Add(new SelectListItem{ Text ="West Delhi", Value = "2" });
localities.Add(new SelectListItem{ Text ="North Delhi", Value = "3" });
localities.Add(new SelectListItem { Text = "South Delhi", Value = "4" });
break;
}
return Json(new SelectList(localities, "Value", "Text"));
}


and the action method for the last sub locality drop down which changes with the change in locality name is like this---

public JsonResult LoadSubLocalities(string id)
{
List<SelectListItem> sublocalities = new List<SelectListItem>();
switch (id)
{
case"1":
sublocalities.Add(new SelectListItem { Text = "Select your sublocality", Value = "0" });
sublocalities.Add(new SelectListItem { Text = "Region1", Value = "1" });
sublocalities.Add(new SelectListItem { Text = "Region2", Value = "2" });
break;
}
return Json(new SelectList(sublocalities, "Value", "Text"));
}


now the view page is something like this------

<!DOCTYPE html>
<head>
<title></title>
<script src="~/Scripts/jquery-2.1.4.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
</head>
<body>
<div id="map_canvas" style="width: 800px; height: 700px; float:left"></div>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)

<fieldset>
<legend>Enter the Project Details</legend>
<div class="editor-label">
@Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
@if (ViewData.ContainsKey("City")){
@Html.DropDownListFor(model => model.City, ViewData["City"] as List<SelectListItem>, new { style = "width:250px", @class = "DropDown1"})
@Html.ValidationMessageFor(model => model.City)
}
</div>

<div class="editor-label">
@Html.LabelFor(model => model.Locality)
</div>
<div class="editor-field">
@Html.DropDownList("Locality", new SelectList(string.Empty,"Value","Text"),"Please Select a locality", new { style = "width:250px", @class = "DropDown1" })
@Html.ValidationMessageFor(model => model.Locality)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.SubLocality)
</div>
<div class="editor-field">
@Html.DropDownList("SubLocality", new SelectList(string.Empty, "Value", "Text"), "Please Select a sub locality", new { style = "width:250px", @class = "DropDown1" })
@Html.ValidationMessageFor(model => model.SubLocality)
</div>
<p>
<input type="submit" value="Save Project" />
</p>
</fieldset>


Now my javaScript code is something like this where i have written code to fetch city from controller then change locality as the city name changes and change sub locality name with change in locality name-----

<script type="text/javascript">
$(document).ready(function () {
$("#City").change(function () {
$("#Locality").empty();
$.ajax({
type: 'POST',
url: '@Url.Action("LoadLocalities","Project")',
dataType: 'json',
data: { id: $("#City").val() },
success: function (localities) {
$.each(localities, function (i, locality) {
$("#Locality").append('<option value="' + locality.Value + '">' +
locality.Text + '</option>');
});
},
error: function (ex) {
alert('Failed to retreive Locality.' + ex);
}
});
return false;
})
$("#Locality").change(function () {
$("#SubLocality").empty();
$.ajax({
type: 'POST',
url: '@Url.Action("LoadSubLocalities")',
dataType: 'Json',
data: { id: $("Locality").val() },
success: function (sublocalities) {
$.each(sublocalities, function (i, sublocality) {
$("#SubLocality").append('<option value="' + sublocality.Value + '">' +
sublocality.Text + '</option>');
});
},
error: function (ex) {
alert('Failed to retrieve SubLocality.' + ex);
}
});
return false;
})
});
</script>
}


Now, My problem is that my Locality is working fine with change in city name but SubLocality drop down is not working with change in locality name---

Answer

The reason your $("#Locality").change(function () { is not working is because the following line

data: { id: $("Locality").val() },

return undefined. It needs to be

data: { id: $("#Locality").val() }, // add hash

however the correct approach is to use

data: { id: $(this).val() },

in order to avoid traversing the DOM again to get the element with id="Locality"

There are numerous other issues with your code, particularly in respect to validation and returning the view if ModelState is invalid

  1. When generating List<SelectListItem>, do not add the label option (i.e. sublocalities.Add(new SelectListItem { Text = "Select your sublocality", Value = "0" });). You are giving the label option a value which means that its always valid. As it currently is, you may as well delete the @Html.ValidationMessageFor() associated with each dropdown.
  2. Never give the SelectList the same name as the property your binding to (in your case City)
  3. In your LoadLocalities() and LoadSubLocalities() methods you first create List<SelectListItem> and then create a new SelectList (which is IEnumerable<SelectListItem>) so its just unnecessary extra overhead. In any case the client has no knowledge of what a C# class is and you just returning twice as much data across the wire as is necessary (the Selected,Disabled and Group properties which you never use). Instead just pass back a collection of anonymous objects containing 2 properties (for the option value and text)
Comments