javascript MVC 4 Razor - 创建动态 DropDownList
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28117094/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MVC 4 Razor - Creating a dynamic DropDownList
提问by James Harpe
I'm trying to create a view which has two DropDownLists. The options available in the second DropDownList depend upon what the user has selected in the first. I'm passing this data to my view in the ViewBag as follows:
我正在尝试创建一个具有两个 DropDownLists 的视图。第二个 DropDownList 中可用的选项取决于用户在第一个中选择的选项。我将此数据传递给 ViewBag 中的视图,如下所示:
List<SelectListItem> firstBoxChoices = ViewBag.firstBoxChoices;
Dictionary<string, List<SelectListItem>> secondBoxDict = ViewBag.secondBoxDict;
The first object has the choices for the first DropDownList. When the user selects one of those, I need to get the appropriate list of choices for the second DropDownList from my Dictionary. I just can't figure out how to achieve this. If I get the new selection of the first DropDownList in a Javascript onchange() function, there doesn't seem to be any way to use this value as the key for my C# dictionary.
第一个对象可以选择第一个 DropDownList。当用户选择其中一个时,我需要从我的字典中获取适当的第二个DropDownList的选择列表。我只是不知道如何实现这一目标。如果我在 Javascript onchange() 函数中获得第一个 DropDownList 的新选择,似乎没有任何方法可以将此值用作我的 C# 字典的键。
Of course, I've seen this functionality on the web so I know it must be possible somehow. How can I achieve this?
当然,我在网上看到过这个功能,所以我知道它一定是可能的。我怎样才能做到这一点?
Thanks!
谢谢!
回答by Jarga
There are a couple ways of doing this without forcing you to store all the possible data items in the model, my preference is to use Javascript/JQuery. Here is an example of a Country/State cascading drop down:
有几种方法可以在不强制您将所有可能的数据项存储在模型中的情况下执行此操作,我更喜欢使用 Javascript/JQuery。以下是国家/州级联下拉列表的示例:
Javascript used to get states when a country is selected:
用于在选择国家/地区时获取状态的 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>
Country dropdown:
国家下拉列表:
@Html.DropDownListFor(model => model.Country, new SelectList(Model.Countries, "Value", "Text", Model.PreviousCountrySelected), "(Select One)", new { id = "countries_ddl", onchange = "OnCountriesChange(this)" })
State dropdown:
状态下拉列表:
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" })
Controller method to retrieve states:
检索状态的控制器方法:
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);
}
The idea is that on selection of dropdown 1 you use ajax to go retrieve your second dropdown's value.
这个想法是,在选择下拉列表 1 时,您使用 ajax 来检索第二个下拉列表的值。
Edit:Forgot to include utility method for constructing urls
编辑:忘记包含用于构建 url 的实用方法
回答by James Harpe
The .change
event of your first select should populate the second select by calling a server method that returns the option data based on the selected value. Given the following view model
第.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; }
}
Controller
控制器
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);
}
View
看法
@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)
....
Script
脚本
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));
});
});
});