MVC 4 Razor - 创建一个动态下拉列表

5

我正在尝试创建一个视图,其中包括两个下拉列表。第二个下拉列表中可用的选项取决于用户在第一个下拉列表中选择了什么。我将此数据通过ViewBag传递到我的视图,如下所示:

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

第一个对象包含第一个下拉列表的选择。当用户选择其中之一时,我需要从我的字典中获取适当的第二个下拉列表的选项列表。我只是想不出如何实现这一点。如果我在Javascript onchange()函数中获取第一个下拉列表的新选择,似乎没有任何办法将其作为C#字典的键使用。

当然,我在网页上看到过这个功能,所以我知道它一定是可能的。我该如何实现这个呢?

谢谢!

2个回答

10

有几种方法可以做到这一点,而不强制您将所有可能的数据项存储在模型中,我更喜欢使用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的实用方法。


这正是我正在寻找的!谢谢。 - James Harpe

4
你的第一个选框的.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));
    });
  });
});

也是一个很好的答案。谢谢! - James Harpe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接