Comment utiliser les tirets dans les attributs HTML-5 data- * dans ASP.NET MVC

325

J'essaie d'utiliser des attributs de données HTML5 dans mon projet ASP.NET MVC 1. (Je suis un débutant en C # et ASP.NET MVC.)

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

Les "données-détails" dans les htmlAttributes ci-dessus donnent l'erreur suivante:

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

Cela fonctionne lorsque j'utilise data_details, mais je suppose que cela doit commencer par "data-" conformément aux spécifications.

Mes questions:

  • Existe-t-il un moyen de faire fonctionner cela et d'utiliser des attributs de données HTML5 avec Html.ActionLink ou des aides Html similaires?
  • Existe-t-il un autre mécanisme alternatif pour attacher des données personnalisées à un élément? Ces données doivent être traitées ultérieurement par JS.
Shameem
la source
5
c'est une vieille question avec une réponse obsolète - les utilisateurs de MVC 3 et plus devraient voir cette question stackoverflow.com/questions/2897733/…
ED-209

Réponses:

115

Mise à jour: MVC 3 et les versions plus récentes ont un support intégré pour cela. Voir la réponse très appréciée de JohnnyO ci-dessous pour les solutions recommandées.

Je ne pense pas qu'il existe d'auxiliaires immédiats pour y parvenir, mais j'ai deux idées à essayer:

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

Juste des idées, je ne l'ai pas testé.

Morten Mertner
la source
5
Salut. Si vous souhaitez utiliser la 1ère approche, assurez-vous simplement que votre dictionnaire est de type Dictionary <String, Object>.
Ondrej Stastny
40
Bien que cela fonctionne techniquement, la méthode recommandée (à partir de MVC 3) consiste à utiliser un trait de soulignement à la place du trait d'union (comme l'a souligné JohnnyO).
Curtis achète le
3
Confondre le monde entier avec cette réponse choisie jusqu'à remarquer la vraie réponse ci-dessus!
Rubens Mariuzzo
648

Ce problème a été résolu dans ASP.Net MVC 3. Ils convertissent désormais automatiquement les traits de soulignement des propriétés d'attribut html en tirets. Ils ont eu de la chance sur celui-ci, car les traits de soulignement ne sont pas légaux dans les attributs html, donc MVC peut impliquer en toute confiance que vous souhaitez un tiret lorsque vous utilisez un trait de soulignement.

Par exemple:

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

rendra ceci dans MVC 3:

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

Si vous utilisez toujours une ancienne version de MVC, vous pouvez imiter ce que fait MVC 3 en créant cette méthode statique que j'ai empruntée au code source de 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;
    }
}

Et puis vous pouvez l'utiliser comme ceci:

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

et cela rendra l'attribut data- * correct:

<input data-bind="foo" id="City" name="City" type="text" value="" />
Johnny Oshika
la source
6
Cela ne fonctionne pas pour moi pour une raison quelconque. La source de vue affiche data_ *. Utilisation de MVC3. Des idées?
Simon Hartcher
Salut Simon, avez-vous résolu votre problème? Sinon, pouvez-vous fournir votre code qui vous pose problème?
Johnny Oshika
Toujours pas de chance avec WebGrid.GetHtml(htmlAttributes: new { data_some : "thing" }). : '(
Rubens Mariuzzo
+1 pour indiquer pourquoi les soulignés fonctionneraient. Il ne m'est pas venu à l'esprit que les traits de soulignement n'étaient pas valides dans les noms d'attribut pour HTML!
Umar Farooq Khawaja
2
@RubensMariuzzo, cela n'est pas RouteValueDictionaryintégré dans les Html.Something()méthodes de MVC3 . Il est possible que la version WebGridn'ait pas été mise à niveau de la même manière, ou vous pouvez vérifier la version sur leSystem.Web.Helpers.dll
Keith
58

C'est encore plus facile que tout ce qui est suggéré ci-dessus. Les attributs de données dans MVC qui incluent des tirets (-) sont pris en charge avec l'utilisation du trait de soulignement (_).

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

Je vois que JohnnyO l'a déjà mentionné.

Oliver
la source
12
La méthode responsable est la suivante: HtmlHelper.AnonymousObjectToHtmlAttributes (object), au cas où quelqu'un se demanderait pourquoi son extension personnalisée ne remplacerait pas le trait de soulignement par un trait d'union.
Nikkelmann
1
Cela a vraiment besoin d'être voté car c'est de loin la réponse la plus simple et fonctionne parfaitement!
Dan Diplo
21

En mvc 4 pourrait être rendu avec Underscore ("_")

Le rasoir:

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

Html rendu

<a class="votes" data-fid="18587" data-jid="9" href="/Home/%23/18587">Vote</a>
mzonerz
la source
salut, existe-t-il un moyen de POSTER la transmission de données au contrôleur, via un Ajax ou de soumettre. se demandant comment tirer parti des données. Par exemple, si j'avais un data-dateattribut, comment pourrais-je le publier sur le contrôleur / l'action? Aussi ce qui est% 23 là
transformateur
Oui, utilisez la collection de formulaires et accédez-y avec un ID ou un nom, et% 23 est #
mzonerz
4

Vous pouvez l'implémenter avec une nouvelle fonction d'extension d'assistance HTML qui sera ensuite utilisée de manière similaire aux ActionLinks existants.

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

Et vous l'appelez comme ça ...

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

Simples :-)

Éditer

un peu plus d'écrire ici

WestDiscGolf
la source
3

J'ai fini par utiliser un lien hypertexte normal avec Url.Action, comme dans:

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

C'est plus laid, mais vous avez un peu plus de contrôle sur le atag, ce qui est parfois utile dans les sites fortement AJAXifiés.

HTH

Keith Williams
la source
0

Je n'aime pas utiliser une balise "a" pure, trop de frappe. Je viens donc avec une solution. En vue, il semble

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

Implémentation de la 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
la source
1
Il y a sûrement un meilleur nom de classe ... un extra tà la fin au moins!
hvaughan3
-2

Vous pouvez l'utiliser comme ceci:

En Mvc:

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

En Html:

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