EditorFor () et propriétés html

113

Les versions d'aperçu d'Asp.Net MVC 2.0 fournissent des aides comme

Html.EditorFor(c => c.propertyname)

Si le nom de la propriété est une chaîne, le code ci-dessus rend une texbox.

Que faire si je souhaite 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, cela ne rend pas les modèles par défaut utilisables.

chandmk
la source

Réponses:

92

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

@Html.TextBoxFor(c => c.PropertyName, new { style = "width: 500px;" })
WEFX
la source
62
@vondip. Assurez-vous que c'est une TEXTBOX et non un EDITEUR. Ne travaillez pas avec l'éditeur.
Kasper Skov
1
Il fonctionne également avec les zones de texte: @ Html.TextAreaFor (c => c.PropertyName, new {style = "width: 500px;"})
Tarzan
Notez que certaines annotations de données ne sont pas prises en charge par TextBoxFor, qui fonctionnerait avec EditorFor, comme FormatString
AaronLS
14
Cette réponse n'ignore-t-elle pas totalement le sujet de la question, à savoir la fonctionnalité EditorFor-Template?
Philipp M du
1
Cependant, l'utilisation de TextBoxFor désactive les formats d'affichage définis comme annotations de données
Anders Lindén
61

J'ai résolu cela 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!

tjeerdhans
la source
1
brillant - j'avais une liste déroulante DateHeure de sélection de date que j'avais déjà modélisée, mais lui transmettre des attributs supplémentaires s'avérait douloureux - cela a résolu le problème pour moi, merci!
Terry_Brown
EditorFor avec maxlength ne fonctionne pas pour moi (TextBoxFor d'autre part)
Drejc
@tjeerdhans, j'ai utilisé ce code pour personnaliser mon css. Cela fonctionne mais malheureusement, il remplace les valeurs css d'origine. Comment puis-je l' ajouter au CSS d'origine à la place?
Rosdi Kasim
33

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

Styliser un assistant @ 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 comme "jj MMM aaaa"

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

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

wayne.blackmon
la source
1
Cela a très bien fonctionné pour moi aussi dans MVC4.
atconway
1
Le formatage a fonctionné mais maintenant null est retourné pour les données désactivant effectivement la boîte.
Joe
2
Je ne sais pas ce que c'est avec les gens de MVC, c'est comme si personne n'avait écrit un site Web qui fonctionne avec plusieurs langues et formats pour les nombres.
adudley
Très bien. C'est simple, cela fonctionne et cela répond en fait à la question du PO, au lieu de fournir des alternatives. Utilisation de MVC4.
draconis
Avertissement: DateTimes semble s'afficher comme type = "datetime", ce qui est incorrect pour une date de naissance, et certains navigateurs (comme Firefox mobile) prennent en charge correctement ce type d'entrée, y compris un composant d'heure qui ne passera probablement pas la validation et est difficile ou impossible pour l'utilisateur de supprimer.
brianary
25

Peut-être voudra-t-il consulter l'article du blog de Kiran Chand , il utilise des métadonnées personnalisées sur le modèle de vue, 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 propre et simple à mon avis, mais j'aimerais voir ce cas d'utilisation courant intégré à mvc.

tj.
la source
71
Est-ce que vous plaisantez? C'est beaucoup trop exagéré pour une chose aussi simple. De plus en plus, je retourne au HTML pur et j'oublie les méthodes d'aide gonflées MVC. Il y a 5 minutes, j'avais un simple TextboxFor qui a lancé avec succès un datepicker jquery. Maintenant, juste parce que je voulais changer la façon dont il formate la valeur de date pré-chargée, j'ai dû le changer en EditorFor. Mais maintenant, tout à coup, je ne peux plus spécifier mes propres attributs HTML sans écrire ces méthodes et aides d'extension personnalisées trop gonflées. Quelle blague. Il doit y avoir un moyen plus simple, vous les professeurs fous ne savez pas quand vous arrêter.
Aaron
1
Je pense que vous mélangez les contextes. Comment pouvez-vous avoir deux appels EditorFor différents, chacun obtenant ses propres valeurs de taille et de longueur maximale avec le lien que vous avez fourni? Si vous ne souhaitez pas utiliser EditorFor, vous pouvez toujours utiliser TextBox helper ou simple html. Mais ce n'est pas la question!
chandmk
@Aaron à partir du dernier MVC, vous pouvez spécifier des attributs html supplémentaires avec EditorForen le passant comme new { htmlAttributes: { @class = "yourclass" } }
suit
17

Je suis surpris que personne n'ait mentionné le passer dans "additionalViewData" et le lire 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"])) %>
Ismaël Smyrnow
la source
Sur cette base, j'ai créé un assistant qui prend en compte la fusion des attributs - stackoverflow.com/a/11498094/79842
Colin Bowern
6

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

Faites dériver votre modèle 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 la chaîne. Le deuxième formulaire rendra le modèle personnalisé.

La 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 le faire dans la vue, vous pouvez également 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 la classe TemplateViewModel de base - un terrain d'entente 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 ;-)

reine3
la source
Je pense qu'une meilleure façon de gérer cela est comme je l'ai mentionné ici stackoverflow.com/questions/1647609/… ... En bref, faire quelque chose de similaire à la façon dont WPF gère le problème ... Éléments de styles arbitraires (dans ce cas attributs) sont passés au modèle et le modèle décide à quel élément interne il appliquera le style ...
vdhant
6

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

Joe Kahl
la source
Cela fonctionne très bien pour apporter des modifications CSS spécifiques au contrôle lors de l'utilisation du EditorFormodèle. J'utilise MVC4 et cela a très bien fonctionné.
atconway
6

Comme dans 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 sur ce blog

Geai
la source
3

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

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

C'est ce qu'on appelle System.ComponentModel.DataAnnotations. Si vous ne trouvez pas ce ValidationAttributedont vous avez besoin, vous pouvez toujours définir des attributs personnalisés.

Meilleures salutations, Carlos

Carlos Fernandes
la source
3
Il parle d'attributs HTML comme maxlength et non validation.
Mathias F
J'espère que le moteur de vue obéiraient aux DataAnnotations aussi. Je n'ai pas encore joué avec MVC2.
mxmissile
J'ai essayé l'annotation de données StringLength. Cela ne fonctionnait pas avec EditorFor.
wayne.blackmon
3

Ce n'est peut-être pas la solution la plus astucieuse, mais elle est simple. Vous pouvez écrire une extension dans la classe HtmlHelper.EditorFor. Dans cette extension, vous pouvez fournir un paramètre d'options qui écrira les options dans ViewData pour l'assistant. 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 d'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 c'est simple et clair pour la pauvre âme qui doit maintenir votre code sur la route. Et il est facile d'étendre à diverses autres informations que vous souhaitez transmettre à vos modèles. Cela fonctionne bien jusqu'à présent pour moi dans un projet où j'essaie d'envelopper autant que possible dans un ensemble de modèles pour aider à standardiser le HTML environnant, à la http://bradwilson.typepad.com/blog/2009/ 10 / aspnet-mvc-2-templates-part-5-master-page-templates.html .

place
la source
3

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

Ajout de la prise en charge des attributs html pour les modèles - ASP.Net MVC 2.0 Beta

chandmk
la source
L'idée de mettre des propriétés de mise en forme HTML sur le modèle (vue) va à l'encontre de l'idée de MVC de séparer la vue et la logique! Et si le modèle avait besoin de différentes représentations en HTML?
saintedlama
2
@Saintedlama: C'est parfaitement bien de mettre des annotations de données sur le viewmodel , car le seul but de viewmodel est de fournir un modèle de données structuré pour la vue . À ne pas confondre avec model , qui dans la terminologie MVC représente généralement une entité DB, qui ne doit pas avoir de propriétés liées à la vue. Cela dit, il est malheureux que ses annotations de viewmodel commencent par HTMLxxx car cela implique HTML comme couche de présentation, mais une ligne doit être dessinée quelque part. :) De plus, s'il réutilise le viewmodel pour, disons, l'application silverlight, il peut facilement ajouter des attributs SL à son viewmodel.
Boris B.
3

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 la validation fonctionne.

Piotr Czyż
la source
dont vous avez besoin@class = "className"
JoeBrockhaus
2

Dans ma pratique, j'ai trouvé qu'il est 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é.

Étant 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">
Dmitry Efimenko
la source
2

Parce que la question est pour EditorFor not TextBoxFor, la suggestion de 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 changer TOUS vos EditorFors car il s'avère que MVC définit la classe des 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;
}

De plus, vous pouvez définir le style pour

input[type="text"] {
    width: 200px;
}
  • cela remplace .text-box et changera toutes les zones de texte d'entrée, EditorFor ou autre.
stuartdotnet
la source
Toutes les zones de texte EditorFor () ne sont pas de type input = "text". Les propriétés DateTime semblent s'afficher sous la forme type = "datetime".
brianary
2

J'ai également eu un problème avec la définition de la largeur de TextBox dans MVC3, tandis que la définition de 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, new {Class = "textBox", style = "width: 90%;"})

également dans ce cas, les validations fonctionnent parfaitement.

Ashish
la source
2

Une façon de contourner le problème est d'avoir des délégués sur le modèle de vue pour gérer l'impression d'un rendu spécial comme celui-ci. J'ai fait cela pour une classe de pagination, j'expose une propriété publique sur le modèleFunc<int, string> RenderUrl pour y faire face.

Alors définissez comment le bit personnalisé sera écrit:

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

Sortez la vue de la Pagingclasse:

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

... et pour la Pagingvue 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 pourrait être considéré comme trop compliqué, mais j'utilise ces téléavertisseurs partout et je ne supporte pas de voir le même code standard pour les rendre.

Phil Cooper
la source
1

MISE À JOUR: hm, évidemment cela ne fonctionnera pas car le modèle est passé par valeur donc les attributs ne sont pas préservés; mais je laisse cette réponse comme une idée.

Une autre solution, je pense, serait d'ajouter vos propres helpers 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.

reine3
la source
0

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})
Zielot
la source
0

Je l'ai résolu !!
Pour Razor, la syntaxe est la suivante:
@Html.TextAreaFor(m=>m.Address, new { style="Width:174px" })ceci ajuste la largeur de la zone de texte à la largeur que j'ai définie dans le paramètre de style.
Pour ASPx, la syntaxe est la suivante:
<%=Html.TextAreaFor(m => m.Description, new { cols = "20", rows = "15", style="Width:174px" })%>
cela fera l'affaire

Sorangwala Abbasali
la source