Mars_serg
Mars_serg

Reputation: 13

MVC 4 Ajax DropDownList

There are two DropDownLists on a form.

If the user chooses a Region in the first DropDownList, there should be only cities related to this region in the second DropDownList.

I already tried solutions that I found on StackOverflow, but because of my beginner knowledge of jQuery and MVC, I failed. Maybe there is a difference between my model/controller and others, that these DropDownLists are already on form and they should be dynamically changed using ajax.

Html

<div class="form-group col-sm-4">
    @Html.LabelFor(m => m.Company.Region.Name)
    @Html.DropDownList("region", Model.Regions, new { @class = "form-control" ,@id = "Region_drop" })
</div>

<div class="form-group col-sm-4">
    @Html.LabelFor(m => m.Company.City.Name)
    @Html.DropDownList("city", Model.Cities, new { @class = "form-control" ,@id = "City_drop" })
</div>

Controller

[Authorize]
public ActionResult AddCompany()
{
    CompanyModel company = new CompanyModel();
    SelectList regions = new SelectList(db.Regions, "Id", "Name");
    SelectList cities = new SelectList(db.Cities, "Id", "Name");

    AddCompanyViewModel acvm = new AddCompanyViewModel
    {
        Regions = regions,
        Cities = cities,
    };

    return View(acvm);
}

Model

public class RegionModel
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Display(Name = "Регион")]
    [Required]
    public string Name { get; set; }

    public IEnumerable<CompanyModel> Companies { get; set; }
    public IEnumerable<CityModel> Cities { get; set; }
}

public class CityModel
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Display(Name = "Город")]
    [Required]
    public string Name { get; set; }

    public int RegionId { get; set; }
    public RegionModel Region { get; set; }

    public IEnumerable<CompanyModel> Companies { get; set; }
}

Updated: I tried to write a secondary ActionResult for getting data from DB

[HttpPost]
public ActionResult getCitiesAction(int provinceId)
{
    var cities = db.Cities.Where(a => a.RegionId == provinceId).Select(a => "<option value='" + a.Id + "'>" + a.Name + "'</option>'");

    return Content(String.Join("", cities));
}

And then added some JS, as recommended in one of the other solutions:

$("#Region_drop").change(function () {
  $.ajax({
    url: "getCitiesAction",
    type: "post",
    data: {
      provinceId: $("#Region_drop").val()
    }
  }).done(function (response) {
    $("#City_drop").html(response);
  });
});

After running this in the browser, and making some break points, it shows the region ID, but after calling ajax the function dies.

Upvotes: 0

Views: 841

Answers (1)

Shyju
Shyju

Reputation: 218702

While your code will work (except it will add an extra ' as suffix to the option text, It is not a great idea to mix UI markup with C# code which generates the data. With your current code your action method is generating a string needed to render the options.

I suggest to not build a string in your action method for your options markup. Return a json array. In this way you can use the same method if you want to render a list of table rows/divs/list items using the same action method. Also less payload you are transferring from server.

[HttpPost]
public ActionResult getCitiesAction(int provinceId)
{
    var cities = db.Cities
                   .Where(a => a.RegionId == provinceId)
                   .Select(a => new SelectListItem { Value=a.Id.ToString(), Text=a.Name})
                   .ToList()

    return Json(cities);
}

Now in your ajax done event, loop through this array and create an option item, set the text and value attribute values and add it to the SELECT element

).done(function (response) {
    $("#City_drop").empty();
    $.each(response,function(i,item)
    {
        $("#City_drop").append($("<option>").text(item.Text).val(item.Value));
    });   
});

Upvotes: 2

Related Questions