0
votes

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.

1
please show what you tried and how it fails - perhaps it isn't very far from working correctly and can be fixed easily. At the moment there is no evidence, apart from your words, that you actually attempted to do this.ADyson
@ADyson updated question, thanks for respond.Mars_serg

1 Answers

2
votes

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));
    });   
});