lunes, 26 de abril de 2010
Resulta algo paradójico que ASP.NET MVC sea capaz de generar código para comprobar tanto en cliente como en servidor que la longitud del texto introducido sea menor que la indicada con la anotación
Podemos comprobarlo muy fácilmente. Por ejemplo, dada una entidad del Modelo como la siguiente:
Es decir, los validadores automáticos, tanto en cliente como en servidor, nos avisan de que hemos superado el número máximo de caracteres a introducir, pero no se impide que esto se produzca mediante el atributo
Afortunadamente hay varias formas de solucionar este pequeño inconveniente, como creando nuevos helpers o utilizando plantillas de edición personalizadas. En este post veremos cómo implementar la primera opción, creando un helper que realice la tarea de forma automática.
El código del helper es el siguiente, y lo comento brevemente justo a continuación:
En primer lugar, estamos accediendo a los metadatos de la propiedad partiendo de la expresión lambda que recibimos como parámetro. Desde estos metadatos obtenemos, si existe, el validador asociado al atributo
Una vez obtenido el validador, buscamos en éste la información que será suministrada a los scripts en cliente, en particular el valor del parámetro “maximumLength”, introduciéndolo en la colección de atributos HTML que finalmente se envía al helper original asociando este valor al atributo
Ahora, para simplificar las llamadas al helper desde las vistas, creamos un par de sobrecargas, similares a las que utilizamos normalmente en
Y eso es todo. Si sustituimos en nuestras vistas las llamadas a
Podéis encontrar el código fuente completo en Skydrive.
Publicado en: Variable not found.
Hey, ¿sabes que estoy en Twitter?
[StringLength]
, y sin embargo, los helpers habituales no generen el atributo maxlength
en el tag <input type="text">
.Podemos comprobarlo muy fácilmente. Por ejemplo, dada una entidad del Modelo como la siguiente:
public class Persona
{
[StringLength(20, ErrorMessage="Máximo {1} caracteres")]
public string Nombre { get; set; }
}
Si creamos su vista de edición por defecto e introducimos en ella los validadores en cliente, obtendremos en tiempo de ejecución un resultado como el que podemos apreciar en la siguiente captura de pantalla:
maxlength
de la etiqueta el tag <input type="text">
.Afortunadamente hay varias formas de solucionar este pequeño inconveniente, como creando nuevos helpers o utilizando plantillas de edición personalizadas. En este post veremos cómo implementar la primera opción, creando un helper que realice la tarea de forma automática.
Html.LimitedTextBoxFor()
Vale, sé que no es un nombre estupendo para el helper, pero de momento va a tener que valer con ese ;-P. La idea es que podamos generar text boxes que limiten el número de caracteres permitidos en función de lo indicado en las anotaciones del Modelo. Es decir, sobre el ejemplo anterior, ocurriría lo siguiente:// En la vista:
<%= Html.LimitedTextBoxFor(model => model.Nombre ) %>
// HTML resultante:
<input id="Nombre" maxlength="20" name="Nombre" type="text" value="" />
El código del helper es el siguiente, y lo comento brevemente justo a continuación:
public static MvcHtmlString LimitedTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TProperty>> expression,
IDictionary<string, object> htmlAttributes)
{
// Obtenemos los metadatos de la propiedad
ModelMetadata metadata =
ModelMetadata.FromLambdaExpression(expression, html.ViewData);
// Obtenemos la información utilizada para validar el tamaño del texto
ControllerContext cctx = html.ViewContext.Controller.ControllerContext;
StringLengthAttributeAdapter stringLengthValidator =
metadata.GetValidators(cctx)
.OfType<StringLengthAttributeAdapter>()
.FirstOrDefault();
if (stringLengthValidator != null)
{ // Si hay validación de este tipo...
var parms = stringLengthValidator
.GetClientValidationRules()
.First()
.ValidationParameters;
// Obtenemos el valor del
int maxlength = (int)parms["maximumLength"]; // tamaño máximo para el texto...
if (htmlAttributes == null)
htmlAttributes = new RouteValueDictionary();
htmlAttributes.Add("maxlength", maxlength); // y añadimos el atributo maxlength
}
return html.TextBoxFor(expression, htmlAttributes);
}
En primer lugar, estamos accediendo a los metadatos de la propiedad partiendo de la expresión lambda que recibimos como parámetro. Desde estos metadatos obtenemos, si existe, el validador asociado al atributo
[StringLength]
, que es de tipo StringLengthAttributeAdapter
.Una vez obtenido el validador, buscamos en éste la información que será suministrada a los scripts en cliente, en particular el valor del parámetro “maximumLength”, introduciéndolo en la colección de atributos HTML que finalmente se envía al helper original asociando este valor al atributo
maxlength
de la etiqueta a generar. Ahora, para simplificar las llamadas al helper desde las vistas, creamos un par de sobrecargas, similares a las que utilizamos normalmente en
TextBoxFor()
:public static MvcHtmlString LimitedTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes)
{
return html.LimitedTextBoxFor<TModel, TProperty>(
expression,
((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes))
);
}
public static MvcHtmlString LimitedTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TProperty>> expression)
{
return html.LimitedTextBoxFor(expression, null);
}
Y eso es todo. Si sustituimos en nuestras vistas las llamadas a
TextBoxFor
por LimitedTextBoxFor
tendremos la cuestión solucionada. Otra posibilidad, bastante más cómoda, sería retocar las plantillas de edición generadas por Visual Studio para que incluyan las llamadas a estos nuevos helpers.Podéis encontrar el código fuente completo en Skydrive.
Publicado en: Variable not found.
Hey, ¿sabes que estoy en Twitter?
Aún no hay comentarios, ¡sé el primero!
Enviar un nuevo comentario