【问题标题】:SelectListItem with data-attributes具有数据属性的 SelectListItem
【发布时间】:2013-07-15 23:09:41
【问题描述】:

无论如何要在 ViewModel 上预先填充一个带有数据属性的 SelectList 吗?

我想做

@Html.DropdownListFor(m=> m.CityId, Model.Cities);

所以它会生成如下代码:

<select id="City" class="location_city_input" name="City">
    <option data-geo-lat="-32.522779" data-geo-lng="-55.765835" data-geo-zoom="6" />
    <option data-geo-lat="-34.883611" data-geo-lng="-56.181944" data-geo-zoom="13" data-geo-name="Montevideo" data-child=".state1" value="1">Montevideo</option>               
    <option data-geo-lat="-34.816667" data-geo-lng="-55.95" data-geo-zoom="13" data-geo-name="Canelones, Ciudad de la Costa" data-child=".state41" value="41">Ciudad de la Costa</option>
</select>

【问题讨论】:

    标签: asp.net-mvc html html-helper custom-data-attribute selectlist


    【解决方案1】:

    这是简单的解决方案。

    并非所有内容都必须使用 .NET 代码中的扩展方法编写。 MVC 的一大优点是它使您可以轻松地构建自己的 HTML。

    使用 MVC4,您可以使用帮助器 HTML.NameFor 和 HTML.IdFor 获取表达式树上元素的 ID 和名称

    <select name="@Html.NameFor(Function(model) model.CityId)"
            id="@Html.IdFor(Function(model) model.CityId)"
            class="location_city_input">
        @For Each city In Model.Cities
            @<option value="@city.Value"
                     @(If(city.Value = Model.CityId, "selected", ""))
                     data-geo-lat="@city.Lat"
                     data-geo-lng="@city.Lng"
                     data-geo-zoom="@city.Zoom">
                @city.Text
            </option>
        Next
    </select>
    

    假设Model.Cities 是一组暴露这些属性的项目。那么你应该准备好了。

    如果您想要可重用性,请考虑将其作为可枚举城市的任何内容的编辑器模板

    【讨论】:

    • 有趣...我不知道 html.namefor 等。我会试一试
    • 为您的 html 添加真正轻松的灵活性的好建议。
    • 由于 razor2 你可以简单地做selected="@city.Value == Model.CityId",它会生成正确的标记(selected="selected" 或者什么都没有)
    • 你如何让它在验证的情况下仍然有效?当出现验证错误时,我的选择不再正确地以红色突出显示。
    • @Diego 发布的代码在我添加括号之前不起作用:selected="@(city.Value == Model.CityId)"
    【解决方案2】:

    您必须扩展 SelectListItem,然后扩展 DropDownListFor 才能使用扩展的 SelectListItem。

    看看这个解决方案:

    Adding html class tag under <option> in Html.DropDownList

    【讨论】:

    • 这看起来像是正确的答案,但看起来有点难看。我宁愿自己编写选择而不是扩展 SelectListItem 和 DropDownListFor 我认为。我不确定。
    • 我不知道你为什么认为它丑陋,但对我来说似乎更合乎逻辑。每个SelectListItem代表最终html中的一个option标签,你需要做的是在option标签(SelectListItem)中添加自定义html属性,所以只有扩展SelectListItem才有意义。
    • 我认为从 mvc 框架的角度来看它很难看。但解决办法就是如何处理。
    • 同意,只是添加一些简单的属性就很讨厌:(
    • 真的很丑的解决方案。最新 (5.2) 版本的 MVC 是否已经涵盖了它,或者您仍然需要为此编写自定义代码?谢谢
    【解决方案3】:

    这就是我最终在没有扩展的情况下完成它但仍然启用不显眼的验证以继续工作并绑定到 ViewModel 属性的方式。

    创建了一个 Html Helper 以将验证属性作为字符串获取:

        public static IHtmlString GetUnobtrusiveValidationAttributesFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> propertySelector)
        {
            string propertyName = html.NameFor(propertySelector).ToString();
            ModelMetadata metaData = ModelMetadata.FromLambdaExpression(propertySelector, html.ViewData);
            IDictionary<string, object> attributeCollection = html.GetUnobtrusiveValidationAttributes(propertyName, metaData);
    
            return html.Raw(String.Join(" ", attributeCollection.Select(kvp => kvp.Key + "=\"" + kvp.Value.ToString() + "\"")));
        }
    

    在视图中的 select 列表中使用此帮助器:

    <select name="@Html.NameFor(m => m.CityId)" id="@Html.IdFor(m => m.CityId)"
        @Html.GetUnobtrusiveValidationAttributesFor(m => m.CityId)
        class="location_city_input">
        @foreach(var city in Model.Cities)
        {
            <option value="@city.Id.ToString()" @(city.Id == Model.CityId ? "selected" : "") 
                data-geo-lat="@city.Lat" data-geo-lng="@city.Lng" data-geo-zoom="@city.Zoom">
                @city.Name
            </option>
        }
    </select>
    

    这将输出如下内容:

    <select id="CityId" name="CityId" 
        data-val-required="The SelectedTaxRateID field is required." data-val="true" 
        class="location_city_input">
        <option value="1" selected data-geo-lat="-34.883611" data-geo-lng="-56.181944" data-geo-zoom="13">Montevideo</option>               
        <option value="41" data-geo-lat="-34.816667" data-geo-lng="-55.95" data-geo-zoom="13">Ciudad de la Costa</option>
    </select>
    

    我将把条件 data- 属性留给你,因为这些只是形成适当的 Razor 表达式的问题。

    【讨论】:

      【解决方案4】:

      MVC 将对象名称转换为属性名称时,会将“_”替换为“-”,因此:

      @Html.DropDownList(a=>a.websiteid, Model.GetItems, new{ data_rel="selected" })
      

      不是我的答案,答案是来自 ASP>NET 论坛的关于 bruce (sqlwork.com)。

      How can I add data-rel="selected" attribute into dropdownlistfor htmlAttributes?

      只是想帮忙,因为这使我免于编写黑客代码!享受吧。

      【讨论】:

      • 这只是将data-rel添加到select而不是每个option
      • 很高兴知道,虽然它没有添加所需的属性(如 ParoX 提到的)。
      【解决方案5】:

      我有类似的要求,我创建了一个扩展。希望它对想要创建扩展程序的人有所帮助。

      /*cs file*/
      /*This contains your information with List<vmListItem>*/
      public class vmListItem
      {
         public int Id { get; set; }
         public string Name { get; set; }
         public string Tag { get; set; }
      }
      
      /*This contains the attributes in select, using List<vmAttribute>. Check cshtml */
      public class vmAttribute
      {
         public string Key { get; set; }
         public string Value { get; set; }
      }
      
          /// <summary>
          /// Creates a dropdownlist using a list with data attributes included
          /// </summary>
          /// <param name="helper"></param>
          /// <param name="id">id and name of the select</param>
          /// <param name="attributes">list of attrs for select</param>
          /// <param name="items"><list of options/param>
          /// <param name="idSelected">id selected in option</param>
          /// <param name="tagName">data-tagName you can choose the name of your tag</param>
          /// <param name="textHeader">first option in select</param>
          /// <returns></returns>
          public static MvcHtmlString DropDownListForWithTag(this HtmlHelper helper, string id, List<vmAttribute> attributes, List<vmListItem> items, int idSelected, string tagName = "tag", string textHeader= "")
          {
              var select = new TagBuilder("select");
              select.GenerateId(id);
              select.MergeAttribute("name", id);
              foreach (vmAttribute att in atributos) select.MergeAttribute(att.Key, att.Value);
      
              TagBuilder headerOption = new TagBuilder("option");
              headerOption .MergeAttribute("value", null);
              headerOption .InnerHtml = textHeader;
              select.InnerHtml += headerOption ;
      
              foreach(var item in items)
              {                
                  TagBuilder option = new TagBuilder("option");
                  option.MergeAttribute("value", item.Id.ToString());
                  option.MergeAttribute("data-" + tagName, item.Tag);
                  if (idSelected == item.Id) option.MergeAttribute("selected", "selected");
                  option.InnerHtml = item.Name;
      
                  select.InnerHtml += option.ToString();
              }
      
              return new MvcHtmlString(select.ToString());
          }
      
      /*cshtml file*/
      @Html.DropDownListForWithTag("MovimientoBienMotivoId", new List<vmAttribute> {
                              new vmAttribute("class", "form-control"),
                              new vmAttribute("data-val", "true"),
                              new vmAttribute("data-val-required", "El campo Motivo es obligatorio"),
                              new vmAttribute("onchange", "movValidarCambioMotivo()"),
                          }, (List<vmListItem>)ViewBag.MovimientoBienMotivoId, Model.MovimientoBienMotivoId, "codigo", "Seleccione")
                          @Html.ValidationMessageFor(model => model.ColumnId, "", new { @class = "text-danger" })
      
      
      /*html results*/
      

      【讨论】:

      • 谢谢你最好的解决方案。我定制了这个扩展以满足我的需要。
      猜你喜欢
      • 2012-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多