Jak używać myślników w atrybutach danych HTML-5 * w ASP.NET MVC

325

Próbuję użyć atrybutów danych HTML5 w moim projekcie ASP.NET MVC 1. (Jestem początkującym użytkownikiem C # i ASP.NET MVC.)

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

„Szczegóły danych” w powyższym atrybucie HTML zawierają następujący błąd:

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

Działa, gdy używam data_details, ale myślę, że musi zaczynać się od „data-” zgodnie ze specyfikacją.

Moje pytania:

  • Czy jest jakiś sposób, aby to zadziałało i używać atrybutów danych HTML5 z Html.ActionLink lub podobnymi pomocnikami HTML?
  • Czy istnieje jakiś alternatywny mechanizm dołączania niestandardowych danych do elementu? Dane te będą przetwarzane później przez JS.
Shameem
źródło
5
to jest stare pytanie z nieaktualną odpowiedzią - użytkownicy MVC 3 i wyższych powinni zobaczyć to pytanie stackoverflow.com/questions/2897733/…
ED-209

Odpowiedzi:

115

Aktualizacja: MVC 3 i nowsze wersje mają wbudowaną obsługę tego. Zobacz wysoko ocenioną odpowiedź JohnnyO poniżej, aby znaleźć zalecane rozwiązania.

Nie wydaje mi się, aby byli to bezpośredni pomocnicy, ale mam dwa pomysły do ​​wypróbowania:

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

Tylko pomysły, nie przetestowałem tego.

Morten Mertner
źródło
5
Cześć. Jeśli chcesz zastosować pierwsze podejście, upewnij się, że słownik jest typu Dictionary <String, Object>.
Ondrej Stastny
40
Chociaż technicznie to działa, zalecanym sposobem (zaczynając od MVC 3) jest użycie podkreślenia zamiast myślnika (jak zauważył JohnnyO).
Curtis kupuje
3
Myląc cały świat z tą wybraną odpowiedzią, zauważyłem prawdziwą odpowiedź powyżej!
Rubens Mariuzzo
648

Ten problem został rozwiązany w ASP.Net MVC 3. Teraz automatycznie konwertują podkreślenia we właściwościach atrybutów HTML na myślniki. Mają szczęście w tym, ponieważ podkreślenia nie są legalne w atrybutach HTML, więc MVC może z pewnością sugerować, że chcesz użyć myślnika, gdy używasz podkreślenia.

Na przykład:

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

renderuje to w MVC 3:

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

Jeśli nadal używasz starszej wersji MVC, możesz naśladować to, co robi MVC 3, tworząc tę ​​statyczną metodę, którą pożyczyłem z kodu źródłowego 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;
    }
}

A potem możesz użyć tego w następujący sposób:

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

a to wyrenderuje poprawny atrybut data- *:

<input data-bind="foo" id="City" name="City" type="text" value="" />
Johnny Oshika
źródło
6
Z jakiegoś powodu to nie działa. Wyświetl źródło pokazuje dane_ *. Korzystanie z MVC3. Jakieś pomysły?
Simon Hartcher
Cześć Simon, rozwiązałeś swój problem? Jeśli nie, czy możesz podać kod, który powoduje problem?
Johnny Oshika,
Nadal nie mam szczęścia WebGrid.GetHtml(htmlAttributes: new { data_some : "thing" }). : '(
Rubens Mariuzzo
+1 za określenie, dlaczego mają działać podkreślenia. Nie przyszło mi do głowy, że podkreślenia nie są prawidłowe w nazwach atrybutów HTML!
Umar Farooq Khawaja
2
@RubensMariuzzo nie jest to RouteValueDictionarypowiązane z Html.Something()metodami MVC3 . Możliwe, że WebGridnie został zaktualizowany w ten sam sposób, lub możesz sprawdzić wersję naSystem.Web.Helpers.dll
Keith
58

Jest to nawet łatwiejsze niż wszystko sugerowane powyżej. Atrybuty danych w MVC, które obejmują myślniki (-), są pokrywane za pomocą podkreślenia (_).

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

Widzę, że JohnnyO już o tym wspomniał.

Oliver
źródło
12
Metodą odpowiedzialną za to jest: HtmlHelper.AnonymousObjectToHtmlAttributes (obiekt), na wypadek, gdyby ktoś zastanawiał się, dlaczego ich niestandardowe rozszerzenie nie zastąpi podkreślenia łącznikiem.
Nikkelmann
1
To naprawdę wymaga głosowania, ponieważ jest to zdecydowanie najprostsza odpowiedź i działa idealnie!
Dan Diplo,
21

W mvc 4 Może być renderowany z podkreśleniem („_”)

Brzytwa:

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

Renderowany HTML

<a class="votes" data-fid="18587" data-jid="9" href="/Home/%23/18587">Vote</a>
mzonerz
źródło
cześć, czy istnieje sposób na wysłanie danych do kontrolera za pośrednictwem Ajax lub przesłania. zastanawiasz się, jak wykorzystać dane. Na przykład, jeśli mam data-dateatrybut w, jak mogę go opublikować w kontrolerze / akcji? Także co tam% 23
transformator
Tak, użyj zbioru formularzy i
uzyskaj
4

Możesz to zaimplementować za pomocą nowej funkcji rozszerzenia pomocnika HTML, która będzie następnie używana podobnie do istniejących ActionLinków.

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

I tak to nazywacie ...

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

Simples :-)

edytować

trochę więcej napisz tutaj

WestDiscGolf
źródło
3

Skończyło się na użyciu normalnego hiperłącza wraz z Url.Action, jak w:

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

Jest brzydszy, ale masz nieco większą kontrolę nad atagiem, co czasami jest przydatne w witrynach mocno z AJAXified.

HTH

Keith Williams
źródło
0

Nie lubię używać czystego znacznika „a”, zbyt dużo pisania. Więc przychodzę z rozwiązaniem. W widoku wygląda

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

Implementacja klasy 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
źródło
1
Na pewno jest lepsza nazwa klasy ... tprzynajmniej na końcu!
hvaughan3
-2

Możesz użyć tego w następujący sposób:

W Mvc:

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

W HTML:

<input type="text" name="Id" data_val_number="10"/>
gururaj nadager
źródło