所以我一直在四处寻找并且找不到任何新的"答案。我不确定是否因为答案仍然正确,或者最近没人提出答案。
我有以下课程(为简洁起见):
public class Address {
public int Id { get; set; }
public int CountryId { get; set; }
public Country Country { get; set; }
public int StateProvinceId { get; set; }
public StateProvince StateProvince { get; set; }
}
public class Country {
public int Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
public class StateProvince {
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
public Country Country { get; set; }
}
我正在寻找的是为EditorFor
列表创建DropDownList
/ Country
的最简单但非常可自定义的方法。具体来说,我想将data attributes
添加到option
的每个select
,以便通过javascript我可以通过过滤什么来重新填充select
的{{1}} StateProvince
根据StateProvince
值属于所选Country
。
我已经查看了以下内容(以及更多,但这些是最值得注意的):
事情就是所有这些答案看起来都很棒,但已经超过3 - 4年了。
这些方法仍然有效吗?
data
与Helper
?期望的结果
Template
答案 0 :(得分:2)
因为你真正希望在这里做的是避免使用ajax调用来填充基于第一个的第二个下拉列表,然后是EditorTemplate
(你必须为{{1}生成所有html的地方手动使用{}和<select>
标记,或使用<option>
扩展方法是特别好的解决方案,因为您需要编写大量代码来模拟HtmlHelper
方法的内容在内部进行以确保正确的双向模型绑定,为客户端验证生成正确的DropDownListFor()
属性等。
相反,您可以使用视图模型将所有data-val-*
的集合传递给视图(您的编辑数据,因此始终使用视图模型),将其转换为javascript对象数组,然后在第一个下拉列表的StateProvince
事件,根据所选选项过滤结果,并使用结果在第二个下拉列表中生成选项。
您的视图模型看起来像
.change()
视图将是
public class AddressVM
{
public int? Id { get; set; }
[Display(Name = "Country")]
[Required(ErrorMessage = "Please select a country")]
public int? SelectedCountry { get; set; }
[Display(Name = "State Province")]
[Required(ErrorMessage = "Please select a state province")]
public int? SelectedStateProvince { get; set; }
public IEnumerable<SelectListItem> CountryList { get; set; }
public IEnumerable<SelectListItem> StateProvinceList { get; set; }
public IEnumerable<StateProvinceVM> AllStateProvinces { get; set; }
}
public class StateProvinceVM
{
public int Id { get; set; }
public string Name { get; set; }
public int Country { get; set; }
}
和脚本
@using (Html.BeginForm())
{
@Html.LabelFor(m => m.SelectedCountry)
@Html.DropDownListFor(m => m.SelectedCountry,Model.CountryList, "Please select", new { ... })
@Html.ValidationMessageFor(m => m.SelectedCountry)
@Html.LabelFor(m => m.SelectedStateProvince)
@Html.DropDownListFor(m => m.SelectedStateProvince,Model.StateProvinceList, "Please select", new { ... })
@Html.ValidationMessageFor(m => m.SelectedStateProvince)
....
}
最后,在控制器中,您需要填充SelectLists并允许在// convert collection to javascript array
var allStateProvinces = @Html.Raw(Json.Encode(Model.AllStateProvinces))
var statesProvinces = $('#SelectedStateProvince');
$('#SelectedCountry').change(function() {
var selectedCountry = $(this).val();
// get the state provinces matching the selected country
var options = allStateProvinces.filter(function(item) {
return item.Country == selectedCountry;
});
// clear existing options and add label option
statesProvinces.empty();
statesProvinces.append($('<option></option>').val('').text('Please select'));
// add options based on selected country
$.each(options, function(index, item) {
statesProvinces.append($('<option></option>').val(item.Id).text(item.Name));
});
});
无效时撤消视图,或者在编辑现有数据时(在两种情况下都需要填充SelectLists)。为避免重复代码,请创建私有帮助程序方法
ModelState
然后控制器方法将是(对于private void ConfigureViewModel(AddressVM model)
{
IEnumerable<Country> countries = db.Countries;
IEnumerable<StateProvince> stateProvinces = db.StateProvinces;
model.AllStateProvinces = stateProvinces.Select(x => new StateProvinceVM
{
Id = x.Id,
Name = x.Name,
Country = x.CountryId
});
model.CountryList = new countries.Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.Name
});
if (model.SelectedCountry.HasValue)
{
model.StateProvinceList = stateProvinces.Where(x => x.CountryId == model.SelectedCountry.Value).Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.Name
});
}
else
{
model.StateProvinceList = new SelectList(Enumerable.Empty<SelectListItem>());
}
}
方法)
Create()