Como usar traços nos atributos data-* HTML-5 no ASP.NET MVC

325

Estou tentando usar atributos de dados HTML5 no meu projeto ASP.NET MVC 1. (Sou iniciante em C # e ASP.NET MVC.)

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

Os "dados-detalhes" nos htmlAttributes acima fornecem o seguinte erro:

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

Funciona quando uso dados_detalhes, mas acho que precisa começar com "dados-" conforme as especificações.

Minhas perguntas:

  • Existe alguma maneira de fazer isso funcionar e usar atributos de dados HTML5 com os auxiliares Html.ActionLink ou Html semelhantes?
  • Existe algum outro mecanismo alternativo para anexar dados personalizados a um elemento? Esses dados devem ser processados ​​posteriormente pelo JS.
Shameem
fonte
5
esta é uma questão de idade com resposta ultrapassada - utilizadores do MVC e 3 acima devem exibir esta questão stackoverflow.com/questions/2897733/...
ED-209

Respostas:

115

Atualização: MVC 3 e versões mais recentes têm suporte interno para isso. Veja a resposta altamente votada do JohnnyO abaixo para obter as soluções recomendadas.

Não acho que haja ajudantes imediatos para conseguir isso, mas tenho duas idéias para você tentar:

// 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" ) )%>

Apenas idéias, não testei.

Morten Mertner
fonte
5
Oi. Se você quiser usar a primeira abordagem, verifique se o seu dicionário é do tipo Dictionary <String, Object>.
Ondrej Stastny
40
Enquanto isso tecnicamente funciona, a maneira recomendada (começando com o MVC 3) é usar um sublinhado no lugar do hífen (como JohnnyO apontou).
Curtis Compra
3
Confundindo o mundo inteiro com esta resposta escolhida até perceber a resposta real acima!
Rubens Mariuzzo
648

Esse problema foi solucionado no ASP.Net MVC 3. Agora, eles convertem automaticamente sublinhados nas propriedades de atributo html em traços. Eles tiveram sorte com este, pois os sublinhados não são legais nos atributos html, portanto, o MVC pode sugerir com confiança que você gostaria de um traço ao usar um sublinhado.

Por exemplo:

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

renderizará isso no MVC 3:

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

Se você ainda estiver usando uma versão mais antiga do MVC, poderá imitar o que o MVC 3 está fazendo, criando este método estático que eu emprestei do código-fonte do MVC3:

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;
    }
}

E então você pode usá-lo assim:

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

e isso renderizará o atributo data- * correto:

<input data-bind="foo" id="City" name="City" type="text" value="" />
Johnny Oshika
fonte
6
Isso não funciona para mim por algum motivo. Exibir fonte mostra dados_ *. Usando MVC3. Alguma ideia?
22611 Simon Simoncher
Olá Simon, você resolveu o seu problema? Caso contrário, você pode fornecer seu código que está causando o problema?
Johnny Oshika
Ainda sem sorte com WebGrid.GetHtml(htmlAttributes: new { data_some : "thing" }). : '(
Rubens Mariuzzo 26/11
+1 para especificar por que os sublinhados funcionariam. Não me ocorreu que sublinhados não eram válidos em nomes de atributo para HTML!
Umar Farooq Khawaja
2
@RubensMariuzzo, isso não está incluído RouteValueDictionarynos Html.Something()métodos do MVC3 . É possível que WebGridnão tenha sido atualizado da mesma forma, ou você pode verificar a versão noSystem.Web.Helpers.dll
Keith
58

É ainda mais fácil do que tudo sugerido acima. Os atributos de dados no MVC que incluem traços (-) são atendidos com o uso de sublinhado (_).

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

Eu vejo JohnnyO já mencionado isso.

Oliver
fonte
12
O método responsável por isso é: HtmlHelper.AnonymousObjectToHtmlAttributes (object), caso alguém esteja se perguntando por que sua extensão personalizada não substituirá o sublinhado por um hífen.
Nikkelmann
1
Isso realmente precisa ser votado, pois é de longe a resposta mais simples e funciona perfeitamente!
precisa
21

No mvc 4 pode ser renderizado com sublinhado ("_")

Navalha:

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

Html renderizado

<a class="votes" data-fid="18587" data-jid="9" href="/Home/%23/18587">Vote</a>
mzonerz
fonte
oi, existe uma maneira de enviar os dados fid para o controlador, através de um Ajax ou enviar. querendo saber como aproveitar os dados. Por exemplo, se eu tivesse um data-dateno atributo, como eu poderia publicá-lo no controlador / ação? Também o que é% 23 lá
transformador
Sim coleção forma de uso e acesso com ID ou nome, e% 23 é #
mzonerz
4

Você pode implementar isso com uma nova função de extensão auxiliar de HTML, que será usada de maneira semelhante aos ActionLinks existentes.

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));
}

E você chama assim ...

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

Simples :-)

editar

um pouco mais de escrever aqui

WestDiscGolf
fonte
3

Acabei usando um hiperlink normal junto com Url.Action, como em:

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

É mais feio, mas você tem um pouco mais de controle sobre a atag, que às vezes é útil em sites fortemente com AJAX.

HTH

Keith Williams
fonte
0

Eu não gosto de usar a tag "a" pura, digitando demais. Então eu venho com solução. Em vista, parece

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

Implementação da classe 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));
    }
}
msa.im
fonte
1
Certamente existe um nome de classe melhor ... tpelo menos um extra no final!
hvaughan3
-2

Você pode usá-lo assim:

No Mvc:

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

Em HTML:

<input type="text" name="Id" data_val_number="10"/>
gururaj nadager
fonte