EditorFor () y propiedades html

113

Las compilaciones de vista previa de Asp.Net MVC 2.0 proporcionan ayudantes como

Html.EditorFor(c => c.propertyname)

Si el nombre de la propiedad es una cadena, el código anterior representa un texbox.

¿Qué sucede si quiero pasar las propiedades MaxLength y Size al cuadro de texto o mi propia propiedad de clase CSS?

¿Necesito crear una plantilla para cada combinación de tamaño y longitud en mi aplicación? Si es así, eso no hace que las plantillas predeterminadas sean utilizables.

Chandmk
fuente

Respuestas:

92

En MVC3, puede establecer el ancho de la siguiente manera:

@Html.TextBoxFor(c => c.PropertyName, new { style = "width: 500px;" })
WEFX
fuente
62
@vondip. Asegúrese de que sea un TEXTBOX y no un EDITOR. Doenst trabaja con el editor.
Kasper Skov
1
También funciona con áreas de texto: @ Html.TextAreaFor (c => c.PropertyName, new {style = "width: 500px;"})
Tarzán
Tenga en cuenta que algunas anotaciones de datos no son compatibles con TextBoxFor, que funcionaría con EditorFor, como FormatString
AaronLS
14
¿No ignora esta respuesta por completo de qué se trata la pregunta, es decir, la funcionalidad Editor para plantilla?
Philipp M
1
Sin embargo, usar TextBoxFor desactiva los formatos de visualización que se establecen como anotaciones de datos
Anders Lindén
61

Resolví esto creando un EditorTemplate llamado String.ascx en mi carpeta / 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 }) %>

En mi opinión, uso

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

¡Funciona como un encanto para mí!

tjeerdhans
fuente
1
brillante: tenía un selector de fechas desplegable DateTime que ya había creado con una plantilla, pero pasarle atributos adicionales estaba resultando doloroso; esto lo resolvió para mí, ¡gracias!
Terry_Brown
EditorFor con maxlength no funciona para mí (TextBoxFor en el otro sí)
Drejc
@tjeerdhans, utilicé este código para personalizar mi css. Funciona, pero desafortunadamente reemplaza los valores originales de CSS. ¿Cómo puedo agregarlo al CSS original?
Rosdi Kasim
33

Ninguna de las respuestas en este o cualquier otro hilo sobre la configuración de atributos HTML para @ Html.EditorFor me ayudó mucho. Sin embargo, encontré una gran respuesta en

Aplicar estilo a un @ Html.EditorFor helper

Utilicé el mismo enfoque y funcionó a la perfección sin escribir mucho código adicional. Tenga en cuenta que se establece el atributo id de la salida html de Html.EditorFor. El código de vista

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

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

La propiedad del modelo con anotación de datos y formato de fecha como "dd MMM aaaa"

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

Funcionó a la perfección sin escribir mucho código adicional. Esta respuesta usa ASP.NET MVC 3 Razor C #.

wayne.blackmon
fuente
1
A mí también me funcionó muy bien en MVC4.
atconway
1
El formateo funcionó, pero ahora se devuelve nulo para los datos que deshabilitan efectivamente el cuadro.
Joe
2
No sé qué pasa con la gente de MVC, es como si nadie hubiera escrito un sitio web que funcione con múltiples idiomas y formatos para números.
adudley
Muy bien. Esto es simple, funciona y en realidad responde a la pregunta del OP, en lugar de proporcionar alternativas. Usando MVC4.
Draconis
Advertencia: DateTimes parece representarse como type = "datetime", lo cual es incorrecto para una fecha de nacimiento, y algunos navegadores (como Firefox mobile) realmente admiten correctamente ese tipo de entrada, incluido un componente de hora que probablemente no pasará la validación y es difícil o imposible que el usuario lo elimine.
brianary
25

Es posible que desee ver la publicación del blog de Kiran Chand , él usa metadatos personalizados en el modelo de vista, como:

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

Esto se combina con plantillas personalizadas que hacen uso de los metadatos. En mi opinión, un enfoque limpio y simple, pero me gustaría ver este caso de uso común integrado en mvc.

tj.
fuente
71
¿Estás bromeando? Esto es demasiado para algo tan simple. Cada vez vuelvo más al HTML puro y me olvido de los métodos de ayuda inflados de MVC. Hace 5 minutos tenía un TextboxFor simple que lanzó con éxito un jquery datepicker. Ahora, solo porque quería cambiar la forma en que formatea el valor de fecha precargado, tuve que cambiarlo a EditorFor. Pero ahora, de repente, ya no puedo especificar mis propios atributos HTML sin escribir estos métodos de extensión personalizados y ayudantes demasiado inflados. Que broma. Tiene que haber una forma más sencilla, ustedes, profesores locos, no saben cuándo parar.
Aaron
1
Creo que estás mezclando contextos. ¿Cómo puede tener dos llamadas EditorFor diferentes y cada una de ellas obtiene su propio tamaño y valores de longitud máxima con el enlace que proporcionó? Si no desea utilizar EditorFor, siempre puede utilizar el asistente TextBox o html simple. ¡Pero esa no es la pregunta!
chandmk
@ Aaron a partir de la última MVC, puede especificar atributos html adicionales EditorForpasándolo como:new { htmlAttributes: { @class = "yourclass" } }
JoeBrockhaus
17

Me sorprende que nadie haya mencionado pasarlo en "additionalViewData" y leerlo en el otro lado.

Ver (con saltos de línea, para mayor claridad):

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

Plantilla de editor:

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

<%= Html.TextBox("", Model, ViewData["htmlAttributes"])) %>
Ismael Smyrnow
fuente
Sobre esta base, creé un ayudante que tiene en cuenta la combinación de atributos - stackoverflow.com/a/11498094/79842
Colin Bowern
6

El problema es que su plantilla puede contener varios elementos HTML, por lo que MVC no sabrá a cuál aplicar su tamaño / clase. Tendrás que definirlo tú mismo.

Haga que su plantilla se derive de su propia clase llamada 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
  }

}

En la plantilla puede hacer esto:

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

En su opinión, sí:

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

El primer formulario representará la plantilla predeterminada para la cadena. El segundo formulario representará la plantilla personalizada.

La sintaxis alternativa utiliza una interfaz fluida:

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

Tenga en cuenta que en lugar de hacer esto en la vista, también puede hacerlo en el controlador, o mucho mejor en el 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) });
}

También tenga en cuenta que puede hacer que la clase TemplateViewModel base, un terreno común para todas sus plantillas de vista, contendrá soporte básico para atributos / etc.

Pero, en general, creo que MVC v2 necesita una mejor solución. Todavía es Beta, pídelo ;-)

queen3
fuente
Creo que una mejor manera de lidiar con esto es como mencioné aquí stackoverflow.com/questions/1647609/… ... En resumen, hacer algo similar a la forma en que WPF maneja el problema ... Elementos de estilos arbitrarios (en este caso atributos) se pasan a la plantilla y la plantilla decide a qué elemento interno aplicará el estilo ...
vdhant
6

Creo que usar CSS es el camino a seguir. Ojalá pudiera hacer más con la codificación .NET, como en XAML, pero en el navegador, CSS es el rey.

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
fuente
Esto funciona muy bien para realizar cambios de CSS específicos de control cuando se usa la EditorForplantilla. Estoy usando MVC4 y esto funcionó muy bien.
atconway
6

Al igual que en MVC 5, si desea agregar algún atributo, simplemente puede hacerlo

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

Información encontrada en este blog

Arrendajo
fuente
3

Puede definir atributos para sus propiedades.

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

Esto se conoce como System.ComponentModel.DataAnnotations. Si no puede encontrar el ValidationAttributeque necesita, siempre puede definir atributos personalizados.

Saludos cordiales, Carlos

Carlos Fernandes
fuente
3
Habla de atributos Html como maxlength no validación.
Mathias F
Yo espero que el motor de vista sería obedecer las DataAnnotations también. Todavía no he jugado con MVC2.
mxmissile
Probé la anotación de datos StringLength. No funcionó con EditorFor.
wayne.blackmon
3

Puede que esta no sea la solución más hábil, pero es sencilla. Puede escribir una extensión para la clase HtmlHelper.EditorFor. En esa extensión, puede proporcionar un parámetro de opciones que escribirá las opciones en ViewData para el asistente. Aquí hay un código:

Primero, el método de extensión:

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

A continuación, el objeto de opciones:

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.
}

Y finalmente, aquí está la línea de la plantilla String.ascx:

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

Francamente, creo que esto es sencillo y claro para el pobrecito que tiene que mantener su código en el futuro. Y es fácil de ampliar para varios otros bits de información que le gustaría pasar a sus plantillas. Me está funcionando bien hasta ahora en un proyecto en el que estoy tratando de envolver todo lo que puedo en un conjunto de plantillas para ayudar a estandarizar el html circundante, a la http://bradwilson.typepad.com/blog/2009/ 10 / aspnet-mvc-2-templates-part-5-master-page-templates.html .

Mancha
fuente
3

Escribí una entrada de blog para responder mi propia pregunta.

Adición de compatibilidad con atributos html para plantillas - ASP.Net MVC 2.0 Beta

Chandmk
fuente
La idea de poner propiedades de formato HTML en el modelo (vista) va en contra de la idea de MVC de separar la vista y la lógica. ¿Qué pasa si el modelo necesita diferentes representaciones en HTML?
saintedlama
2
@Saintedlama: Está perfectamente bien poner anotaciones de datos en el modelo de vista , porque el único propósito del modelo de vista es proporcionar un modelo de datos estructurado para la vista . No debe confundirse con el modelo , que en la terminología de MVC generalmente representa una entidad de base de datos, que no debe tener propiedades relacionadas con la vista. Dicho esto, es lamentable que las anotaciones de su modelo de vista comiencen con HTMLxxx porque eso implica HTML como una capa de presentación, pero hay que trazar una línea en alguna parte. :) Además, si reutiliza el modelo de vista para, por ejemplo, la aplicación Silverlight, puede agregar fácilmente atributos SL a su modelo de vista.
Boris B.
3

No sé por qué no funciona para Html.EditorFor pero probé TextBoxFor y funcionó para mí.

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

... y también funciona la validación.

Piotr Czyż
fuente
necesitas@class = "className"
JoeBrockhaus
2

En mi práctica, descubrí que es mejor usar EditorTemplates con solo un HtmlHelper, TextBox que es en la mayoría de los casos. Si quiero una plantilla para una estructura html más compleja, escribiré un HtmlHelper por separado.

Dado que podemos colocar todo el objeto ViewData en lugar de htmlAttributes del TextBox. Además podemos escribir algún código de personalización para algunas de las propiedades de ViewData si necesitan un tratamiento especial:

@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)

A continuación se muestran los ejemplos de la sintaxis en la vista y el html generado:

@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
fuente
2

Porque la pregunta es para EditorFor no TextBoxFor, la sugerencia de WEFX no funciona.

Para cambiar cuadros de entrada individuales, puede procesar la salida del método EditorFor:

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

También es posible cambiar TODOS sus EditorFors, ya que MVC establece la clase de cuadros de texto EditorFor con .text-box , por lo tanto, puede anular este estilo, en su hoja de estilo o en la página.

.text-box {
    width: 80em;
}

Además, puede establecer el estilo para

input[type="text"] {
    width: 200px;
}
  • esto anula .text-box y cambiará todos los cuadros de texto de entrada, EditorFor o de otro modo.
stuartdotnet
fuente
No todos los cuadros de texto EditorFor () son tipo de entrada = "texto". Las propiedades de DateTime parecen representarse como type = "datetime".
brianary
2

También tuve problemas con la configuración del ancho de TextBox en MVC3, mientras que la configuración del atributo Clsss funcionó para el control TextArea pero no para el control TextBoxFor o EditorFor control:

Intenté seguir y eso funcionó para mí:

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

También en este caso las Validaciones están funcionando perfectamente.

Ashish
fuente
2

Una forma de evitarlo es tener delegados en el modelo de vista para manejar la impresión de renderizado especial como este. Hice esto para una clase de paginación, expongo una propiedad pública en el modelo Func<int, string> RenderUrlpara lidiar con ella.

Así que defina cómo se escribirá el bit personalizado:

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

Genere la vista para la Pagingclase:

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

... y para la Pagingvista real :

@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>
}

Podría verse como un asunto demasiado complicado, pero uso estos buscapersonas en todas partes y no soportaba ver el mismo código repetitivo para renderizarlos.

Phil Cooper
fuente
1

ACTUALIZACIÓN: hm, obviamente esto no funcionará porque el modelo se pasa por valor, por lo que los atributos no se conservan; pero dejo esta respuesta como idea.

Otra solución, creo, sería agregar sus propios ayudantes TextBox / etc, que verificarán sus propios atributos en el modelo.

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

Este es más fácil pero no tan conveniente / flexible.

queen3
fuente
0

Realmente me gustó la respuesta de @tjeerdans que utiliza el EditorTemplate llamado String.ascx en la carpeta / Views / Shared / EditorTemplates. Parece ser la respuesta más sencilla a esta pregunta. Sin embargo, quería una plantilla que usara la sintaxis de Razor. Además, parece que MVC3 usa la plantilla String como predeterminada (consulte la pregunta de StackOverflow " plantilla de visualización mvc para cadenas se usa para enteros "), por lo que debe configurar el modelo como objeto en lugar de cadena. Mi plantilla parece estar funcionando hasta ahora:

@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
fuente
0

¡¡Lo resolví !!
Para Razor, la sintaxis es:
@Html.TextAreaFor(m=>m.Address, new { style="Width:174px" })esto ajusta el ancho del área de texto al ancho que definí en el parámetro de estilo.
Para ASPx, la sintaxis es:
<%=Html.TextAreaFor(m => m.Description, new { cols = "20", rows = "15", style="Width:174px" })%>
esto hará el truco

Sorangwala Abbasali
fuente