James
James

Reputation: 1501

Pass Selected Drop Down List Value to Controller Action and then Populate Another Drop Down List Based on Value

I am trying to select a manufacturer from a list and then based on what manufacturer the user selects, populate a list of models.

View:

<div class="form-group">
        @Html.LabelFor(model => model.Manufacturer.ManufacturerName, "Model",
            htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-5">
            @Html.DropDownList("ManufacturerID", (List<SelectListItem>)ViewBag.Manufacturers,
                htmlAttributes: new { @class = "form-control" })
            @Html.ValidationMessageFor(model => model.Manufacturer.ManufacturerName, "",
                new { @class = "text-danger", onchange = "PopulateModels()" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Model.ModelName, "Model",
            htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-5">
            @Html.DropDownList("ModelID", (List<SelectListItem>)ViewBag.Models,
                htmlAttributes: new { @class = "form-control" })
            @Html.ValidationMessageFor(model => model.Model.ModelName, "",
                new { @class = "text-danger" })
        </div>
    </div>

    <script>
         function PopulateModels()
         {
              var url = '@Html.Raw(Url.Action("GetModelList", "FaultController", new { manufacturer="ManufacturerID" }))';
              window.location = url;
         }
    </script>

Controller:

public List<SelectListItem> GetModelList(Manufacturer manufacturer)
    {
        List<SelectListItem> modelList = new List<SelectListItem>();

        var models = db.Models.Where(m => m.ManufacturerID == manufacturer.ManufacturerID);

        foreach (Model model in models)
        {
            modelList.Add(new SelectListItem
            {
                Text = model.ModelName,
                Value = model.ModelID.ToString()
            });
        }

        var sortedModelList = (from model in modelList
                               orderby model.Text
                               select model).ToList();

        return sortedModelList;
    }

public ActionResult Create(...)
    {
        .
        .
        .

        ViewBag.Models = new List<SelectListItem>();
        ViewBag.Manufacturers = GetManufacturerList();
    }

As you can see, the ViewBag for Models is initially empty, when a manufacturer is selected I want this ViewBag to be updated with all of the models that hold that manufacturer.

I feel like I'm close but cannot figure out what to next, a point in the right direction would be great. I'm also not sure if what I have done so far is completely correct, so if anyone can spot anything I've overlooked or any suggestions on how to improve my code would also be appreciated.

I hope this makes sense, any help is appreciated, thanks in advance.

Updated Code:

View:

<div class="form-group">
        @Html.LabelFor(model => model.Manufacturer.ManufacturerName, "Model",
            htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-5">
            @Html.DropDownList("ManufacturerID", (List<SelectListItem>)ViewBag.Manufacturers,
                htmlAttributes: new { @class = "form-control" , @id= "Manufacturers" })
            @Html.ValidationMessageFor(model => model.Manufacturer.ManufacturerName, "",
                new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Model.ModelName, "Model",
            htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-5">
            @Html.DropDownList("ModelID", (List<SelectListItem>)ViewBag.Models,
                htmlAttributes: new { @class = "form-control" , @id = "Models"})
            @Html.ValidationMessageFor(model => model.Model.ModelName, "",
                new { @class = "text-danger" })
        </div>
    </div>

    <script type="text/javascript">
         $(function(){
          $("#Manufacturers").change(function(){
             var v= $(this).val();
             $("#Models").empty();
             $.getJSON("@Url.Action("GetModels","Fault")?id="+v,function(data){
                 $.each(data,function(a,b){
                   $("#Models").append('<option value="'+b.Value+'">'+b.Text+'</option>');
                 });
             });
          });

        });
    </script>

Controller:

public ActionResult GetModels(int id)
    {
        var models = db.Models.Where(m => m.ManufacturerID == id)
                       .Select(x => new SelectListItem
                       {
                           Value = x.ModelID.ToString(),
                           Text = x.ModelName
                       }).ToList();
        return Json(models, JsonRequestBehavior.AllowGet);

    }

Upvotes: 1

Views: 2221

Answers (1)

Shyju
Shyju

Reputation: 218702

Your current code is making the browser to navigate to the other action method. But what you ideally need is to get this data using ajax and use that to build the SELECT options for the second dropdown.

So setup a change event handler for the first dropdiwn.

$(function(){
  $("#ManufacturerID").change(function(){
     var v= $(this).val();
     $("#Models").empty();
     $.getJSON("@Url.Action("GetModels","YourControlleName")?id="+v,function(data){
         $.each(data,function(a,b){
           $("#Models").append('<option value="'+b.Value+'">'+b.Text+'</option>');
         });
     });
  }); 

});

Now you have a GetModels action method which accepts the manufacturer id in Id parameter and return the corresponding model.

public ActionResult GetModels(int id)
{
   var models = db.Models.Where(m => m.ManufacturerID == id)
                  .Select(x=>new SelectListItem { Value=x.Id.ToString(),
                                                  Text=x.Name}).ToList();
   return Json(models,JsonRequestBehavior.AllowGet);

}

Here is a working dotnetfiddle with dummy data for your reference.

Upvotes: 2

Related Questions