web-dev-qa-db-fra.com

EditorFor () et les propriétés HTML

Les versions d’aperçu Asp.Net MVC 2.0 fournissent des aides telles que 

Html.EditorFor(c => c.propertyname)

Si le nom de la propriété est string, le code ci-dessus restitue une texbox.

Et si je veux transmettre les propriétés MaxLength et Size à la zone de texte ou à ma propre propriété de classe css?

Dois-je créer un modèle pour chaque combinaison de taille et de longueur dans mon application? Si tel est le cas, les modèles par défaut ne sont pas utilisables.

112
chandmk

J'ai écrit une entrée de blog pour répondre à ma propre question

Ajout de la prise en charge d'attributs HTML pour les modèles - ASP.Net MVC 2.0 Beta

3
chandmk

Dans MVC3, vous pouvez définir la largeur comme suit:

@Html.TextBoxFor(c => c.PropertyName, new { style = "width: 500px;" })
91
WEFX

J'ai résolu ce problème en créant un EditorTemplate nommé String.ascx dans mon dossier/Views/Shared/EditorTemplates:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>
<% int size = 10;
   int maxLength = 100;
   if (ViewData["size"] != null)
   {
       size = (int)ViewData["size"];
   }
   if (ViewData["maxLength"] != null)
   {
       maxLength = (int)ViewData["maxLength"];
   }
%>
<%= Html.TextBox("", Model, new { Size=size, MaxLength=maxLength }) %>

À mon avis, j'utilise

<%= Html.EditorFor(model => model.SomeStringToBeEdited, new { size = 15, maxLength = 10 }) %>

Fonctionne comme un charme pour moi!

61
tjeerdhans

Aucune des réponses de ce fil, ni d'aucun autre, sur la définition des attributs HTML pour @ Html.EditorFor ne m'aide beaucoup. Cependant, j'ai trouvé une excellente réponse à 

Styling d'une aide @ Html.EditorFor

J'ai utilisé la même approche et cela a fonctionné à merveille sans écrire beaucoup de code supplémentaire. Notez que l'attribut id de la sortie html de Html.EditorFor est défini. Le code de vue

<style type="text/css">
#dob
{
   width:6em;
}
</style>

@using (Html.BeginForm())
{
   Enter date: 
   @Html.EditorFor(m => m.DateOfBirth, null, "dob", null)
}

La propriété de modèle avec l'annotation des données et le formatage de la date sous la forme "jj MMM aaaa"

[Required(ErrorMessage= "Date of birth is required")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd MMM yyyy}")]
public DateTime DateOfBirth { get; set; }

Travaillé comme un charme sans écrire beaucoup de code supplémentaire. Cette réponse utilise ASP.NET MVC 3 Razor C #.

33
wayne.blackmon

Peut-être voudrez-vous regarder Le blog de Kiran Chand , il utilise des métadonnées personnalisées sur le modèle d'affichage, telles que:

[HtmlProperties(Size = 5, MaxLength = 10)]
public string Title { get; set; }

Ceci est combiné avec des modèles personnalisés qui utilisent les métadonnées. Une approche simple et propre à mon avis, mais j'aimerais voir ce cas d'utilisation commun intégré à mvc. 

25
tj.

Je suis surpris que personne n'ait mentionné le passage dans "additionalViewData" et sa lecture de l'autre côté.

Vue (avec sauts de ligne, pour plus de clarté):

<%= Html.EditorFor(c => c.propertyname, new
    {
        htmlAttributes = new
        {
            @class = "myClass"
        }
    }
)%>

Modèle de l'éditeur:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>

<%= Html.TextBox("", Model, ViewData["htmlAttributes"])) %>
17
Ishmael Smyrnow

Je pense que l'utilisation de CSS est la voie à suivre. J'aimerais pouvoir faire plus avec le codage .NET, comme en XAML, mais dans le navigateur, le CSS est roi.

Site.css 

#account-note-input { 
  width:1000px; 
  height:100px; 
} 

.cshtml

<div class="editor-label"> 
  @Html.LabelFor(model => model.Note) 
</div> 
<div class="editor-field"> 
  @Html.EditorFor(model => model.Note, null, "account-note-input", null) 
  @Html.ValidationMessageFor(model => model.Note) 
</div>

Joe

6
Joe Kahl

À partir de MVC 5, si vous souhaitez ajouter des attributs, vous pouvez simplement faire

 @Html.EditorFor(m => m.Name, new { htmlAttributes = new { @required = "true", @anotherAttribute = "whatever" } })

Informations trouvées dans ce blog

6
Jay

Le problème est que votre modèle peut contenir plusieurs éléments HTML. Par conséquent, MVC ne saura pas à qui appliquer votre taille/classe. Vous devrez le définir vous-même.

Faites en sorte que votre modèle dérive de votre propre classe appelée TextBoxViewModel:

public class TextBoxViewModel
{
  public string Value { get; set; }
  IDictionary<string, object> moreAttributes;
  public TextBoxViewModel(string value, IDictionary<string, object> moreAttributes)
  {
    // set class properties here
  }
  public string GetAttributesString()
  {
     return string.Join(" ", moreAttributes.Select(x => x.Key + "='" + x.Value + "'").ToArray()); // don't forget to encode
  }

}

Dans le modèle, vous pouvez faire ceci:

<input value="<%= Model.Value %>" <%= Model.GetAttributesString() %> />

À votre avis, vous faites:

<%= Html.EditorFor(x => x.StringValue) %>
or
<%= Html.EditorFor(x => new TextBoxViewModel(x.StringValue, new IDictionary<string, object> { {'class', 'myclass'}, {'size', 15}}) %>

Le premier formulaire rendra le modèle par défaut pour string. Le second formulaire rendra le modèle personnalisé.

Une syntaxe alternative utilise une interface fluide:

public class TextBoxViewModel
{
  public string Value { get; set; }
  IDictionary<string, object> moreAttributes;
  public TextBoxViewModel(string value, IDictionary<string, object> moreAttributes)
  {
    // set class properties here
    moreAttributes = new Dictionary<string, object>();
  }

  public TextBoxViewModel Attr(string name, object value)
  {
     moreAttributes[name] = value;
     return this;
  }

}

   // and in the view
   <%= Html.EditorFor(x => new TextBoxViewModel(x.StringValue).Attr("class", "myclass").Attr("size", 15) %>

Notez qu'au lieu de faire cela dans la vue, vous pouvez aussi le faire dans le contrôleur, ou bien mieux dans le ViewModel:

public ActionResult Action()
{
  // now you can Html.EditorFor(x => x.StringValue) and it will pick attributes
  return View(new { StringValue = new TextBoxViewModel(x.StringValue).Attr("class", "myclass").Attr("size", 15) });
}

Notez également que vous pouvez créer une classe de base TemplateViewModel - une base commune pour tous vos modèles de vue - qui contiendra un support de base pour les attributs/etc.

Mais en général, je pense que MVC v2 a besoin d’une meilleure solution. C'est toujours Beta - allez le demander ;-)

6
queen3

Vous pouvez définir des attributs pour vos propriétés.

[StringLength(100)]
public string Body { get; set; }

Ceci s'appelle System.ComponentModel.DataAnnotations. Si vous ne trouvez pas la ValidationAttribute dont vous avez besoin, vous pouvez toujours définir des attributs personnalisés.

Cordialement, Carlos

3
Carlos Fernandes

Ce n'est peut-être pas la solution la plus simple, mais c'est simple. Vous pouvez écrire une extension à la classe HtmlHelper.EditorFor. Dans cette extension, vous pouvez fournir un paramètre d'options qui écrira les options dans ViewData pour l'aide. Voici un code:

Tout d'abord, la méthode d'extension:

public static MvcHtmlString EditorFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, TemplateOptions options)
{
    return helper.EditorFor(expression, options.TemplateName, new
    {
        cssClass = options.CssClass
    });
}

Ensuite, l'objet options:

public class TemplateOptions
{
    public string TemplateName { get; set; }
    public string CssClass { get; set; }
    // other properties for info you'd like to pass to your templates,
    // and by using an options object, you avoid method overload bloat.
}

Et enfin, voici la ligne du modèle String.ascx:

<%= Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = ViewData["cssClass"] ?? "" }) %>

Franchement, je pense que cela est clair et clair pour la pauvre âme qui doit maintenir votre code plus tard. Et il est facile d'étendre d'autres informations que vous souhaitez transmettre à vos modèles. Cela fonctionne bien jusqu'à présent pour moi dans un projet où j'essaye d'envelopper autant que possible dans un ensemble de modèles pour aider à normaliser le code HTML environnant, à la http://bradwilson.typepad.com/blog/ 2009/10/aspnet-mvc-2-templates-part-5-master-page-templates.html .

3
spot

Je ne sais pas pourquoi cela ne fonctionne pas pour Html.EditorFor mais j'ai essayé TextBoxFor et cela a fonctionné pour moi.

@Html.TextBoxFor(m => m.Name, new { Class = "className", Size = "40"})

... et aussi des travaux de validation.

3
Piotr Czyż

Parce que la question est pour EditorFor not la suggestion de TextBoxFor WEFX ne fonctionne pas. 

Pour modifier des zones de saisie individuelles, vous pouvez traiter la sortie de la méthode EditorFor:

<%: new HtmlString(Html.EditorFor(m=>m.propertyname).ToString().Replace("class=\"text-box single-line\"", "class=\"text-box single-line my500pxWideClass\"")) %>

Il est également possible de modifier TOUS vos EditorFors, car MVC définit la classe de zones de texte EditorFor avec .text-box , vous pouvez donc simplement remplacer ce style dans votre feuille de style ou sur la page. 

.text-box {
    width: 80em;
}

En outre, vous pouvez définir le style pour

input[type="text"] {
    width: 200px;
}
  • cela annule .text-box et modifiera toutes les zones de saisie, EditorFor ou autre. 
2
stuartdotnet

Une façon de contourner le problème consiste à demander aux délégués du modèle d'affichage de gérer l'impression d'un rendu spécial comme celui-ci. Je l'ai fait pour une classe de pagination, j'expose une propriété publique sur le modèle Func<int, string> RenderUrl pour la gérer.

Définissez donc comment le bit personnalisé sera écrit:

Model.Paging.RenderUrl = (page) => { return string.Concat(@"/foo/", page); };

Produisez la vue pour la classe Paging:

@Html.DisplayFor(m => m.Paging)

... et pour la vue Paging réelle:

@model Paging
@if (Model.Pages > 1)
{
    <ul class="paging">
    @for (int page = 1; page <= Model.Pages; page++)
    {
        <li><a href="@Model.RenderUrl(page)">@page</a></li>
    }
    </ul>
}

Cela peut sembler excessif, mais j’utilise ces téléavertisseurs un peu partout et ne supporte pas de voir le même code standard pour les obtenir.

2
Phil Cooper

J'avais également un problème avec définir la largeur de TextBox dans MVC3, alors que définir l'attribut Clsss fonctionnait pour le contrôle TextArea mais pas pour le contrôle TextBoxFor ou EditorFor:

J'ai essayé de suivre et cela a fonctionné pour moi:

@ Html.TextBoxFor (model => model.Title, nouveau {Class = "textBox", style = "width: 90%;"})

dans ce cas également, les validations fonctionnent parfaitement.

2
Ashish

Dans ma pratique, j'ai trouvé qu'il était préférable d'utiliser EditorTemplates avec un seul HtmlHelper, TextBox, dans la plupart des cas. Si je veux un modèle pour une structure HTML plus complexe, j'écrirai un HtmlHelper séparé.

Etant donné que nous pouvons coller tout l’objet ViewData à la place de htmlAttributes de la TextBox. De plus, nous pouvons écrire du code de personnalisation pour certaines des propriétés de ViewData si elles nécessitent un traitement spécial:

@model DateTime?
@*
    1) applies class datepicker to the input;
    2) applies additionalViewData object to the attributes of the input
    3) applies property "format" to the format of the input date.
*@
@{
    if (ViewData["class"] != null) { ViewData["class"] += " datepicker"; }
    else { ViewData["class"] = " datepicker"; }
    string format = "MM/dd/yyyy";
    if (ViewData["format"] != null)
    {
        format = ViewData["format"].ToString();
        ViewData.Remove("format");
    }
}

@Html.TextBox("", (Model.HasValue ? Model.Value.ToString(format) : string.Empty), ViewData)

Vous trouverez ci-dessous des exemples de syntaxe dans la vue et le code HTML généré:

@Html.EditorFor(m => m.Date)
<input class="datepicker" data-val="true" data-val-required="&amp;#39;Date&amp;#39; must not be empty." id="Date" name="Date" type="text" value="01/08/2012">
@Html.EditorFor(m => m.Date, new { @class = "myClass", @format = "M/dd" })
<input class="myClass datepicker" data-val="true" data-val-required="&amp;#39;Date&amp;#39; must not be empty." id="Date" name="Date" type="text" value="1/08">
2
Dmitry

C'est le moyen le plus propre et le plus élégant/simple d'obtenir une solution ici.

Brilliant blog post et pas de folie dans l'écriture de méthodes d'extension/helper personnalisées comme un professeur fou.

http://geekswithblogs.net/michelotti/archive/2010/02/05/mvc-2-editor-template-with-datetime.aspx

1
Aaron

UPDATE: hm, évidemment, cela ne fonctionnera pas car le modèle est passé par valeur, ainsi les attributs ne sont pas conservés; mais je laisse cette réponse comme une idée.

Une autre solution, je pense, consisterait à ajouter vos propres assistants TextBox/etc, qui vérifieront vos propres attributs sur le modèle.

public class ViewModel
{
  [MyAddAttribute("class", "myclass")]
  public string StringValue { get; set; }
}

public class MyExtensions
{
  public static IDictionary<string, object> GetMyAttributes(object model)
  {
     // kind of prototype code...
     return model.GetType().GetCustomAttributes(typeof(MyAddAttribute)).OfType<MyAddAttribute>().ToDictionary(
          x => x.Name, x => x.Value);
  }
}

<!-- in the template -->
<%= Html.TextBox("Name", Model, MyExtensions.GetMyAttributes(Model)) %>

Celui-ci est plus facile mais pas aussi pratique/flexible.

1
queen3

J'ai vraiment aimé la réponse @tjeerdans qui utilise le EditorTemplate nommé String.ascx dans le dossier/Views/Shared/EditorTemplates. Cela semble être la réponse la plus simple à cette question. Cependant, je voulais un modèle utilisant la syntaxe Razor. De plus, il semble que MVC3 utilise le modèle String par défaut (voir la question StackOverflow " le modèle d'affichage mvc pour les chaînes est utilisé pour les entiers "). Vous devez donc définir le modèle sur objet plutôt que sur chaîne. Mon modèle semble fonctionner jusqu'à présent:

@model object 

@{  int size = 10; int maxLength = 100; }

@if (ViewData["size"] != null) {
    Int32.TryParse((string)ViewData["size"], out size); 
} 

@if (ViewData["maxLength"] != null) {
    Int32.TryParse((string)ViewData["maxLength"], out maxLength); 
}

@Html.TextBox("", Model, new { Size = size, MaxLength = maxLength})
0
zielot