【问题标题】:MVC 4 Razor - Creating a dynamic DropDownListMVC 4 Razor - 创建动态下拉列表
【发布时间】:2025-11-30 07:05:04
【问题描述】:

我正在尝试创建一个包含两个 DropDownLists 的视图。第二个 DropDownList 中可用的选项取决于用户在第一个中选择的内容。我将这些数据传递给 ViewBag 中的视图,如下所示:

   List<SelectListItem> firstBoxChoices =  ViewBag.firstBoxChoices;
   Dictionary<string, List<SelectListItem>> secondBoxDict = ViewBag.secondBoxDict;

第一个对象具有第一个 DropDownList 的选项。当用户选择其中一个时,我需要从我的字典中获取适当的第二个DropDownList的选择列表。我只是不知道如何实现这一目标。如果我在 Javascript onchange() 函数中获得了第一个 DropDownList 的新选择,似乎没有任何方法可以将此值用作我的 C# 字典的键。

当然,我在网上看到过这个功能,所以我知道它一定是可能的。我怎样才能做到这一点?

谢谢!

【问题讨论】:

    标签: javascript c# .net asp.net-mvc razor


    【解决方案1】:

    有几种方法可以做到这一点,而不会强迫您在模型中存储所有可能的数据项,我更喜欢使用 Javascript/JQuery。以下是国家/州级联下拉列表的示例:

    选择国家/地区时用于获取状态的 Javascript:

    <script type="text/javascript">
        function AppendUrlParamTokens(url, params) {
    
            for (var param in params) {
                if (params[param] == null) {
                    delete params[param];
                }
            }
    
            return url + "?" + jQuery.param(params);
        }
    
        function OnCountriesChange(ddl) {
            jQuery.getJSON(AppendUrlParamTokens('@Url.Action("GetStates", "Data")', { countryId: ddl.options[ddl.selectedIndex].value }), function (result) {
                var target = jQuery('#states_ddl');
                target.empty();
                jQuery(result).each(function() {
                    jQuery(document.createElement('option'))
                        .attr('value', this.Value)
                        .text(this.Text)
                        .appendTo(target);
                });
            });
        };
    </script>
    

    国家下拉菜单:

    @Html.DropDownListFor(model => model.Country, new SelectList(Model.Countries, "Value", "Text", Model.PreviousCountrySelected), "(Select One)", new { id = "countries_ddl", onchange = "OnCountriesChange(this)" })
    

    状态下拉菜单:

    Html.DropDownListFor(model => model.State,
                                  Model.States != null
                                           ? new SelectList(Model.States, "Value", "Text", Model.PreviousStateSelected)
                                           : new SelectList(new List<SelectListItem>(), "Value", "Text"),
                                  new { id = "states_ddl" })
    

    获取状态的控制器方法:

    public ActionResult GetStates(short? countryId)
    {
        if (!countryId.HasValue)
        {
            return Json(new List<object>(), JsonRequestBehavior.AllowGet);
        }
    
        var data = GetAllStatesForCountry(countryId.Value).Select(o => new { Text = o.StateName, Value = o.StateId });
    
        return Json(data, JsonRequestBehavior.AllowGet);
    }
    

    这个想法是,在选择下拉列表 1 时,您使用 ajax 来检索第二个下拉列表的值。

    编辑:忘记包含构造 url 的实用方法

    【讨论】:

    • 这正是我想要的!谢谢。
    【解决方案2】:

    您的第一个选择的.change 事件应通过调用基于所选值返回选项数据的服务器方法填充第二个选择。给定以下视图模型

    public class MyModel
    {
      [Required(ErrorMessage = "Please select an organisation")]
      [Display(Name = "Organisation")]
      public int? SelectedOrganisation { get; set; }
      [Required(ErrorMessage = "Please select an employee")]
      [Display(Name = "Employee")]
      public int? SelectedEmployee { get; set; }
      public SelectList OrganisationList { get; set; }
      public SelectList EmployeeList { get; set; }
    }
    

    控制器

    public ActionResult Edit(int ID)
    {
      MyModel model = new MyModel();
      model.SelectedOrganisation = someValue; // set if appropriate
      model.SelectedEmployee = someValue; // set if appropriate
      ConfigureEditModel(model); // populate select lists
      return View(model);
    }
    
    [HttpPost]
    public ActionResult Edit(MyModel model)
    {
      if(!ModelState.IsValid)
      {
        ConfigureEditModel(model); // reassign select lists
        return View(model);
      }
      // save and redirect
    }
    
    private void ConfigureEditModel(MyModel model)
    {
      // populate select lists
      model.OrganisationList = new SelectList(db.Organisations, "ID", "Name");
      if(model.SelectedOrganisation.HasValue)
      {
        var employees = db.Employees.Where(e => e.Organisation == model.SelectedOrganisation.Value);
        model.EmployeeList = new SelectList(employees, "ID", 
      }
      else
      {
        model.EmployeeList = new SelectList(Enumerable.Empty<SelectListItem>());
      }
    }
    
    [HttpGet]
    public JsonResult FetchEmployees(int ID)
    {
      var employees = db.Employees.Where(e => e.Organisation == ID).Select(e => new
      {
        ID = e.ID,
        Name = e.Name
      });
      return Json(employees, JsonRequestBehavior.AllowGet);
    }
    

    查看

    @model MyModel
    ....
      @Html.LabelFor(m => m.SelectedOrganisation)
      @Html.DropDownListFor(m => m.SelectedOrganisation, Model.OrganisationList, "-Please select-")
      @Html.ValidationMessageFor(m => m.SelectedOrganisation)
      @Html.LabelFor(m => m.SelectedEmployee)
      @Html.DropDownListFor(m => m.SelectedEmployee, Model.EmployeeList, "-Please select-")
      @Html.ValidationMessageFor(m => m.SelectedEmployee)
    ....
    

    脚本

    var url = '@Url.Action("FetchEmployees")';
    var employees = $('SelectedEmployee');
    $('#SelectedOrganisation').change(function() {
      employees.empty();
      if(!$(this).val()) {
        return;
      }
      employees.append($('<option></option>').val('').text('-Please select-'));
      $.getJson(url, { ID: $(this).val() }, function(data) {
        $.each(data, function(index, item) {
          employees.append($('<option></option>').val(item.ID).text(item.Text));
        });
      });
    });
    

    【讨论】:

    • 也是一个很好的答案。谢谢!