Devoneous Devoneous - 4 months ago 14
Ajax Question

Pass value of form field from view to controller via ajax and populate a dropdown city list based on state selection

I am trying to create a state and city dropdown lists. The city is going to populate when the state is selected. I am doing this using ajax. I have everything written, I feel like it should work, and it of course does not. The state dropdown list is pulled from a seperate class containing an enumerable list of all 50 US states. Where as the second dropdown list I have written in my controller with hopes that I could return the Json data to populate the city dropdown.
Here is my razor for the dropdownlistfor's along with my jquery and ajax:

<div class="form-group">
@Html.LabelFor(model => model.State, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.State, WebGridProject.Models.StateCodes.GetStatesList(), new { id = "State", @class = "form-control", @onchange = "FillCity2()" })
@Html.ValidationMessageFor(model => model.State, "", new { @class = "text-danger" })
</div>
</div>


<script>
function FillCity2() {
var stateId = $('#State').val();
console.log(stateId);
$.ajax({
url: '/Home/FillCity2',
type: "GET",
dataType: "JSON",
data: { State: stateId },
success: function (city) { // cities is the variable in the controller made to fetch the city list
$("#City").html("");
$.each(city, function (i , cityNames) {
$("#City").append(
$('<option></option>').val(cityNames.cities));
});
}
});
}
</script>


<div class="form-group">
@Html.LabelFor(model => model.City, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">

@Html.DropDownListFor(model => model.City, new SelectList(Enumerable.Empty<SelectListItem>()), "Select City", new { id = "City", @class = "form-control"})
@Html.ValidationMessageFor(model => model.City, "", new {@class = "text-danger"})
</div>
</div>


Here is the controller action I am using to process the request:

public JsonResult FillCity2(string stateName)
{
List<SelectListItem> cities = new List<SelectListItem>();

switch (stateName)
{
case "AK":
cities = new List<SelectListItem>
{
new SelectListItem() {Text = "", Value = ""},
new SelectListItem() {Text = "Anchorage", Value = "Anchorage"},
new SelectListItem() {Text = "Fairbanks", Value = "Fairbanks"},
};
break;
case "AL":
cities = new List<SelectListItem>
{
new SelectListItem() {Text = "", Value = ""},
new SelectListItem() {Text = "Auburn", Value = "Auburn"},
new SelectListItem() {Text = "Birmingham", Value = "Birmingham"},
new SelectListItem() {Text = "Dothan", Value = "Dothan"},
new SelectListItem() {Text = "Mobile", Value = "Mobile"},
};
break;
case "AZ":
cities = new List<SelectListItem>
{
new SelectListItem() {Text = "", Value = ""},
new SelectListItem() {Text = "Pheonix", Value = "Pheonix"},
new SelectListItem() {Text = "Flagstaff", Value = "Flagstaff"},
new SelectListItem() {Text = "Prescott", Value = "Prescott"},
new SelectListItem() {Text = "Tucson", Value = "Tucson"},
};
break;
case "AR":
cities = new List<SelectListItem>
{
new SelectListItem() {Text = "", Value = ""},
new SelectListItem() {Text = "Fayetteville", Value = "Fayetteville"},
new SelectListItem() {Text = "Fort smith", Value = "Fort smith"},
new SelectListItem() {Text = "Jonesboro", Value = "Jonesboro"},
new SelectListItem() {Text = "Texarkana", Value = "Texarkana"},
};
break;
default:
cities = new List<SelectListItem>
{
new SelectListItem() {Text = "", Value = ""},
new SelectListItem() {Text = "Please Select State", Value = "Please Select State"},
};
break;
}
return Json(cities, JsonRequestBehavior.AllowGet);
}


When I run in debugger the value for #State is showing up as null, although in the console in chrome it shows the actual value (e.g. 'AL' for Alabama, 'AK' for alaska, etc...).

I cant quite figure out where my issue with passing in the value is. And the city list in the debugger just keeps going to the default switch case.

Any ideas?

Answer

Your action method parameter name and the ajax call data parameter name should match. Since your ajax call is sending the selected state value in a parameter called State, you should update your action method to have the same (or the other way)

public JsonResult FillCity2(string state)
{
   //use the state variable in your method now for switch statement
}

Also, Your action method returns an list of SelectListItem,which has a Text and Value property. So you should use either of those properties when building the city dropdown. But you are trying to access the cities property of each item in the list which does not exist.

And the last,thing, you need to set the text of the option as well along with the value. Because text is what the user see.

success: function (cityArray) { 
    $("#City").html("");
    $.each(cityArray, function (i, city) {
        $("#City").append(
            $('<option></option>').val(city.Value).text(city.Text));
    });
}