Mvc EditorTemplate与HtmlHelper一起添加数据属性

时间:2018-02-20 05:29:58

标签: asp.net-mvc asp.net-mvc-5 html-helper mvc-editor-templates

所以我一直在四处寻找并且找不到任何新的"答案。我不确定是否因为答案仍然正确,或者最近没人提出答案。

我有以下课程(为简洁起见):

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年了。

这些方法仍然有效吗?

  • 如果是这样,我为什么要选择dataHelper
  • 如果没有,有什么新方法可以解决这个问题?提供代码示例以与我最终完成的工作进行比较的奖励。

期望的结果

Template

1 个答案:

答案 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()