2016-10-20 2 views
1

J'ai travaillé sur la création d'une méthode d'extension pour un site MVC 5. L'idée de base est qu'elle va créer le balisage pour nos groupes d'entrée (c'est-à-dire mettre dans l'étiquette, les entrées et les messages de validation). Ces groupes auront des classes HTML et CSS standard qui seront toujours présentes. Jusqu'à présent, c'est ce que j'ai et ça marche bien.Comment puis-je ajouter des attributs HTML dynamiques dans MVC 5 à l'aide de EditorFor?

public static MvcHtmlString CreateEditorForGroup<TModel, TProperty>(this HtmlHelper<TModel> helper, 
    Expression<Func<TModel, TProperty>> expression) 
{ 
    TagBuilder editorLabel = new TagBuilder("span"); 
    editorLabel.AddCssClass("form-label"); 
    editorLabel.InnerHtml += helper.LabelFor(expression); 

    TagBuilder wrappingDiv = new TagBuilder("div"); 
    wrappingDiv.InnerHtml = editorLabel.ToString() + helper.EditorFor(expression, new { htmlAttributes = new { @class = "form-control" }}).ToString() + helper.ValidationMessageFor(expression).ToString(); 
    return new MvcHtmlString(wrappingDiv.ToString()); 
} 

Je dois aussi étendre cela un peu plus loin pour permettre une coutume supplémentaire des attributs HTML à transmettre dans (classes CSS supplémentaires, des attributs de données, etc.). Alors je suis arrivé jusqu'ici:

public static MvcHtmlString CreateEditorForGroup<TModel, TProperty>(this HtmlHelper<TModel> helper, 
    Expression<Func<TModel, TProperty>> expression, object htmlAttributesForEditor = null) 
{ 
    TagBuilder editorLabel = new TagBuilder("span"); 
    editorLabel.AddCssClass("form-label"); 
    editorLabel.InnerHtml += helper.LabelFor(expression); 

    var editorHtmlAttributes = MergeHtmlAttributes(htmlAttributesForEditor, new { @class = "form-control" }); 

    TagBuilder wrappingDiv = new TagBuilder("div"); 
    wrappingDiv.InnerHtml = editorLabel.ToString() + helper.EditorFor(expression, new { htmlAttributes = editorHtmlAttributes }).ToString() + helper.ValidationMessageFor(expression); 
    return new MvcHtmlString(wrappingDiv.ToString()); 
} 

(.. Ne vous inquiétez pas à propos de la définition de MergeHtmlAttributes Actuellement, il fonctionne très bien et retourne IDictionary<string, object>) Étant donné que toutes les recherches que je l'avais fait (et mes propres tests) montre que je peux faire le

helper.EditorFor(expression, new { htmlAttributes = new { @class = "form-control" }}) 

et après obtenir le résultat attendu (dans mon cas, une zone de texte avec une « forme de contrôle » classe css). Mais si j'utilise le code qui fusionne les attributs, je ne reçois rien de différent que si j'avais appelé EditorFor sans le second argument (c'est-à-dire que ma zone de texte sort sans aucun ensemble de classes CSS). J'ai donc essayé d'autres choses, comme la fusion des attributs fusionnés en object. Pas de changement. J'ai essayé de convertir les attributs fusionnés en ExpandoObject. Rien. Essayé de couler le ExpandoObject à un object avant de le transmettre. Aucune différence.

Existe-t-il un moyen d'accomplir ceci? Il semble étrange que cela ne fonctionne qu'avec des types anonymes alors que la plupart des autres méthodes (TextBoxFor, etc) peuvent prendre un dictionnaire d'attributs.

(La seule chose que je peux penser à ce stade est de commencer la réécriture/remplaçant les modèles par défaut pour répondre à cette certaine façon. Je préfère ne pas aller dans cette voie si je n'ai pas.)

Répondre

0

Je pense que vous devez changer de htmlAttributes anonyme à RouteValueDictionary

Essayez quelque chose comme ceci:

RouteValueDictionary htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(editorHtmlAttributes); 
... + helper.EditorFor(expression, new { htmlAttributes = htmlAttributes }).ToString() + ... 
+0

Pourquoi un RouteValueDictionary faire une différence? Cela n'a rien à voir avec le routage. – Becuzz

+0

https://cpratt.co/html-editorfor-and-htmlattributes/ – RitchieD

+0

Si vous lisez cet article, il indique que dans MVC 5.1 ils ont corrigé le problème que j'avais en ajoutant la possibilité d'utiliser l'objet anonyme comme je l'étais En l'utilisant. Avec ce correctif, ils ont utilisé un RouteValueDictionary (qui, comme l'admet l'article, est un nom horrible une fois que son utilisation a été étendue). Mais à partir de MVC 5, la seule façon d'y parvenir était de remplacer les modèles par défaut. Donc, votre solution ne résout pas réellement le problème dans MVC 5. La "solution" dans ce cas serait de mettre à niveau vers MVC 5.1 ou supérieur. – Becuzz