具有数据属性的SelectListItem


76

无论如何,是否在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>

Answers:


113

这是简单的解决方案。

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

随着MVC4你可以得到元素的ID和名称上与助手表达式树HTML.NameForHTML.IdFor

<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是一组暴露这些属性的项目。那你应该准备好了。

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


2
有趣的...我不了解html.namefor等。我将尝试一下
Bart Calixto

1
为您的html添加真正简单的灵活性的好建议。
ChandlerPelhams 2015年

5
由于razor2,您可以简单地执行操作selected="@city.Value == Model.CityId",它将生成正确的标记(无论是selected="selected"什么都不是)
Diego

4
您如何使它在验证中仍然有效?发生验证错误时,我的选择不再正确地以红色突出显示。
skeletank

4
@Diego发布的代码在添加括号之前不起作用:selected="@(city.Value == Model.CityId)"
Tawab Wakil

12

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

看一下这个解决方案:

在Html.DropDownList中的<option>下添加html类标记


1
这看起来像是正确的答案,但看起来有点难看。我宁愿自己写选择,也不愿扩展SelectListItem和DropDownListFor。我不确定。
Bart Calixto

4
我不知道您为什么觉得这很丑,但对我来说似乎更合逻辑。每个SelectListItem都代表最终html中的一个选项标签,而您需要做的是向该选项标签(SelectListItem)添加自定义html属性,因此仅扩展SelectListItem是有意义的。
ataravati 2013年

1
我认为从mvc框架的角度来看这很丑陋。但是解决方案就是如何处理。
Bart Calixto

1
同意,很讨厌,只是添加一些简单的属性:(
drogon 2013年

真的很难解决。MVC的最新(5.2)版本中已经涵盖了它,还是您仍然想为此编写自定义代码?谢谢
Aleksander Bethke,2016年

6

这是我最终无需扩展即可完成的方式,但是仍然使不干扰验证的功能继续起作用并绑定到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表达式的问题。


3

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

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

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

如何将data-rel =“ selected”属性添加到htmlAttributes的dropdownlist中?

请帮忙,因为这可以帮助我免去编码的麻烦!请享用。


6
这仅将数据相关性添加select到每个非相关性中option
-ParoX

很高兴知道,尽管它没有按需添加属性(例如提到的ParoX)。
spaark

2

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

/*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*/

在此处输入图片说明


谢谢大家最好的解决方案。我根据自己的需要定制了该扩展名。
哈利
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.