如何在ASP.NET MVC中的HTML-5 data- *属性中使用破折号


325

我正在尝试在ASP.NET MVC 1项目中使用HTML5数据属性。(我是C#和ASP.NET MVC新手。)

 <%= Html.ActionLink("« Previous", "Search",
     new { keyword = Model.Keyword, page = Model.currPage - 1},
     new { @class = "prev", data-details = "Some Details"   })%>

上面的htmlAttributes中的“数据细节”给出以下错误:

 CS0746: Invalid anonymous type member declarator. Anonymous type members 
  must be declared with a member assignment, simple name or member access.

当我使用data_details时,它可以工作,但是我想它必须按照规范以“ data-”开头。

我的问题:

  • 是否有任何方法可以使此工作正常运行,并将HTML5数据属性与Html.ActionLink或类似的Html帮助器一起使用?
  • 是否有其他替代机制可将自定义数据附加到元素?稍后将由JS处理此数据。

5
这是过时的答案一个老问题- MVC 3及以上的用户应该针对这一问题stackoverflow.com/questions/2897733/...
ED-209

Answers:


115

更新:MVC 3和更高版本对此提供了内置支持。有关建议的解决方案,请参见下面JohnnyO的高度赞同的答案。

我认为没有任何直接的帮助者可以实现这一目标,但是我确实有两个想法可供您尝试:

// 1: pass dictionary instead of anonymous object
<%= Html.ActionLink( "back", "Search",
    new { keyword = Model.Keyword, page = Model.currPage - 1},
    new Dictionary<string,Object> { {"class","prev"}, {"data-details","yada"} } )%>

// 2: pass custom type decorated with descriptor attributes
public class CustomArgs
{
    public CustomArgs( string className, string dataDetails ) { ... }

    [DisplayName("class")]
    public string Class { get; set; }
    [DisplayName("data-details")]
    public string DataDetails { get; set; }
}

<%= Html.ActionLink( "back", "Search",
    new { keyword = Model.Keyword, page = Model.currPage - 1},
    new CustomArgs( "prev", "yada" ) )%>

只是想法,还没有测试。


5
你好 如果要使用第一种方法,只需确保字典的类型为Dictionary <String,Object>。
Ondrej Stastny 2010年

40
尽管从技术上讲这是可行的,但推荐的方法(从MVC 3开始)是使用下划线代替连字符(如JohnnyO所指出的)。
Curtis

3
将此选择的答案与全世界混淆,直到注意到上面的真实答案!
Rubens Mariuzzo 2012年

648

ASP.Net MVC 3中已解决此问题。它们现在可以自动将html属性属性中的下划线转换为破折号。他们很幸运,因为下划线在html属性中是不合法的,因此MVC可以自信地暗示您在使用下划线时希望使用破折号。

例如:

@Html.TextBoxFor(vm => vm.City, new { data_bind = "foo" })

将在MVC 3中呈现:

<input data-bind="foo" id="City" name="City" type="text" value="" />

如果您仍在使用旧版本的MVC,则可以通过创建从MVC3的源代码借来的静态方法来模仿MVC 3的操作:

public class Foo {
    public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes) {
        RouteValueDictionary result = new RouteValueDictionary();
        if (htmlAttributes != null) {
            foreach (System.ComponentModel.PropertyDescriptor property in System.ComponentModel.TypeDescriptor.GetProperties(htmlAttributes)) {
                result.Add(property.Name.Replace('_', '-'), property.GetValue(htmlAttributes));
            }
        }
        return result;
    }
}

然后您可以像这样使用它:

<%: Html.TextBoxFor(vm => vm.City, Foo.AnonymousObjectToHtmlAttributes(new { data_bind = "foo" })) %>

这将呈现正确的data- *属性:

<input data-bind="foo" id="City" name="City" type="text" value="" />

6
由于某种原因,这对我不起作用。查看源显示data_ *。使用MVC3。有任何想法吗?
西蒙·哈彻

嗨,西蒙,你解决了你的问题吗?如果没有,您能否提供引起问题的代码?
约翰尼·奥希卡

仍然没有运气WebGrid.GetHtml(htmlAttributes: new { data_some : "thing" })。:'(
鲁本斯·马里努佐

+1,用于指定下划线有效的原因。在我看来,下划线在HTML的属性名称中是无效的!
Umar Farooq Khawaja

2
@RubensMariuzzo并没有RouteValueDictionary加入到MVC3的Html.Something()方法中。可能是WebGrid没有以相同的方式升级,或者您可以在System.Web.Helpers.dll
Keith

58

它比上面建议的一切还要容易。MVC中包含短划线(-)的数据属性通过使用下划线(_)来满足。

<%= Html.ActionLink("« Previous", "Search",
 new { keyword = Model.Keyword, page = Model.currPage - 1},
 new { @class = "prev", data_details = "Some Details"   })%>

我看到JohnnyO已经提到了这一点。


12
负责此操作的方法是:HtmlHelper.AnonymousObjectToHtmlAttributes(object),以防万一有人想知道为什么自定义扩展名不会用连字符替换下划线的情况。
Nikkelmann 2013年

1
这确实需要投票,因为这是迄今为止最简单的答案,而且效果很好!
Dan Diplo

21

在mvc 4中可以用Underscore(“ _”)渲染

剃刀:

@Html.ActionLink("Vote", "#", new { id = item.FileId, }, new { @class = "votes", data_fid = item.FileId, data_jid = item.JudgeID, })

呈现的HTML

<a class="votes" data-fid="18587" data-jid="9" href="/Home/%23/18587">Vote</a>

嗨,有没有一种方法可以通过Ajax或提交将数据文件发布到控制器。想知道如何利用数据。例如,如果我data-date在属性中具有,如何将其发布到控制器/动作?还有那里的%23是什么
变压器

是,使用表单收集并使用ID或名称访问它,%23是#
mzonerz

4

您可以使用新的Html帮助程序扩展功能来实现此功能,然后将其与现有ActionLinks相似地使用。

public static MvcHtmlString ActionLinkHtml5Data(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes, object htmlDataAttributes)
{
    if (string.IsNullOrEmpty(linkText))
    {
        throw new ArgumentException(string.Empty, "linkText");
    }

    var html = new RouteValueDictionary(htmlAttributes);
    var data = new RouteValueDictionary(htmlDataAttributes);

    foreach (var attributes in data)
    {
        html.Add(string.Format("data-{0}", attributes.Key), attributes.Value);
    }

    return MvcHtmlString.Create(HtmlHelper.GenerateLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, null, actionName, controllerName, new RouteValueDictionary(routeValues), html));
}

你这样称呼它...

<%: Html.ActionLinkHtml5Data("link display", "Action", "Controller", new { id = Model.Id }, new { @class="link" }, new { extra = "some extra info" })  %>

简单:-)

编辑

在这里多写一点


3

我最终使用了普通的超链接以及Url.Action,例如:

<a href='<%= Url.Action("Show", new { controller = "Browse", id = node.Id }) %>'
  data-nodeId='<%= node.Id %>'>
  <%: node.Name %>
</a>

这很丑陋,但是您对a标记有更多的控制权,有时在高度AJAX化的网站中很有用。

高温超导


0

我不喜欢使用纯粹的“ a”标签,太多的打字。因此,我提出了解决方案。鉴于它看起来

<%: Html.ActionLink(node.Name, "Show", "Browse", 
                    Dic.Route("id", node.Id), Dic.New("data-nodeId", node.Id)) %>

实施Dic类

public static class Dic
{
    public static Dictionary<string, object> New(params object[] attrs)
    {
        var res = new Dictionary<string, object>();
        for (var i = 0; i < attrs.Length; i = i + 2)
            res.Add(attrs[i].ToString(), attrs[i + 1]);
        return res;
    }

    public static RouteValueDictionary Route(params object[] attrs)
    {
        return new RouteValueDictionary(Dic.New(attrs));
    }
}

1
当然有一个更好的类名... t至少在末尾有一个额外的类名!
hvaughan3

-2

您可以像这样使用它:

在Mvc中:

@Html.TextBoxFor(x=>x.Id,new{@data_val_number="10"});

在HTML中:

<input type="text" name="Id" data_val_number="10"/>
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.