Hoy voy a hablar de un cambio introducido en el framework hace ya algunos años, que, al menos en mi caso, pasó totalmente desapercibido en su momento y durante bastante tiempo después. Y he pensado que sería buena idea publicar sobre ello porque, como este mundo es así de grande, seguro que hay todavía algún despistado al que podría estar afectando a día de hoy y ni siquiera se ha dado cuenta :)
Como recordaréis, los atributos de validación [EmailAddress]
y [Url]
, presentes en el espacio de nombres System.ComponentModel.DataAnnotations
, los hemos utilizado durante años para asegurar que determinados valores de entrada eran direcciones de correo electrónico y URLs válidas, respectivamente:
public class Blog
{
[Required, EmailAddress]
public string ContactEmail { get; set; }
[Required, Url]
public string Url { get; set; }
}
Desde el principio de los tiempos, aún en ASP.NET "clásico", ambos atributos de validación utilizaban internamente complejas expresiones regulares para comprobar los valores, y la verdad es que funcionaban relativamente bien. Nuestras aplicaciones podían confiar en que valores que hubieran superado dichas validaciones serían, como mínimo, sintácticamente correctos y buenos candidatos a ser direcciones de correo o URLs válidas.
Pues bien, desde la llegada de NET 4.7.2, y luego en .NET Core, [EmailAddress]
y [Url]
ya no funcionan así. En palabras casi textuales del equipo de desarrollo, el objeto de estos dos atributos es simplemente prevenir algunos errores básicos al teclear, y no contemplar todas las posibilidades definidas en las respectivas RFC que describen la sintaxis de dichos valores.
Publicado por José M. Aguilar a las 8:05 a. m.
Etiquetas: netcore, netframework, validadores
Publicado por José M. Aguilar a las 9:30 a. m.
Etiquetas: aspnetmvc, desarrollo, trucos, validadores
System.ComponentModel.DataAnnotations
:CreditCardAttribute
, que puede ser utilizado para validar números de tarjeta de crédito.EmailAddressAttribute
, que validará direcciones de correo electrónico.FileExtensionsAttribute
, para validar extensiones en nombres de archivo.PhoneAttribute
, que indica cuándo una propiedad debe contener un número de teléfono válido.UrlAttribute
, que comprobará si el contenido de una propiedad es una URL válida.CompareAttribute
, que antes estaba disponible en System.Web.Mvc y ha “ascendido” a anotación de datos general, permite validar la igualdad de dos propiedades.
También se ha incluido soporte para el atributo
MembershipPasswordAttribute
, recientemente incluido en System.Web.Security
, que comprueba si una contraseña cumple los requisitos establecidos para las mismas en el membership provider.Publicado en Variable not found.
En este post vamos a ver cómo realizar validaciones basadas en anotaciones de forma manual, lo cual puede tener su utilidad en gran número de escenarios.
Los mensajes de error asociados a cada validador son almacenados inicialmente en atributos
data-val-*
sobre el control a comprobar, y cuando se detecta un problema de validación, son mostrados copiando su contenido al interior de la etiqueta <span>
que el helper Html.ValidationMessage()
habrá generado sobre la página.Sin embargo, al hilo de una consulta reciente en los foros de ASP.NET MVC en MSDN, perfectamente contestada por el amigo Eduard Tomás, pensé que realmente tenemos poco control sobre cómo se muestran estos errores, así que me he puesto un rato a ver cómo podíamos conseguir introducir lógica personalizada en este punto aprovechando la flexibilidad que ofrece jQuery validate 1.9.
Salvo por la escasez de documentación de este componente, tomar el control en el momento de mostrar los mensajes de error es bastante sencillo. Basta con establecer una función en la propiedad
showErrors
de los settings
del plugin, cosa que podemos hacer con el siguiente script de inicialización:<script type="text/javascript">
$(function () {
var settings = $.data($('form')[0], 'validator').settings;
settings.showErrors = function (errorMap, errorList) {
// Aquí el código personalizado:
[...]
// Y si nos interesa, finalmente podemos
// ejecutar el comportamiento por defecto
this.defaultShowErrors();
};
});
</script>
(Por simplificar, estamos asumiendo que en el formulario hay un único tag <form>
, que es el que capturamos con el selector).La función
showErrors()
recibe dos parámetros. El primero es un “mapa” donde asociamos a cada clave (nombre del campo) el mensaje de error que tenga asociado. Así, por ejemplo, el valor de errorMap.Nombre
será nulo si el campo “Nombre
” del formulario no tiene ningún error (ha validado correctamente), o el texto del error en caso contrario.En el segundo parámetro de la función encontraremos un array con los errores a mostrar. En cada elemento tendremos disponible la propiedad
element
, desde la que podemos acceder al control que ha generado el error, y message
, donde podemos consultar o establecer la descripción del mismo.Es importante tener en cuenta que la función
showErrors()
es invocada con mucha frecuencia durante el proceso de edición (pérdida de foco, obtención de foco, pulsación de teclas…), por lo que desde el punto de vista de la usabilidad no tiene demasiado sentido introducir en ella procesos bloqueantes (como puede ser un alert()
) o demasiado largos en el tiempo, para evitar que se solapen.Por ejemplo, en el siguiente código utilizamos el efecto “highlight” de jQuery UI para resaltar con un rápido destello el elemento en el que se ha detectado un error:
settings.showErrors = function (errorMap, errorList) {
for (var i = 0; i < errorList.length; i++) {
var error = errorList[i];
// error.element es el elemento que ha provocado el error
$(error.element).effect("highlight", { times: 1 }, 100);
}
this.defaultShowErrors();
};
En fin, algo no demasiado útil ;-P, pero interesante en cualquier caso para profundizar un poco en los misterios e interioridades de jQuery validate.Publicado en Variable not found.
Publicado por José M. Aguilar a las 10:33 a. m.
Etiquetas: aspnetmvc, jquery, scripting, trucos, validadores
El tema, que ha sido propuesto por algunos de vosotros, es sin duda muy interesante. Sea cual sea el tipo de aplicación que desarrollemos, nos vemos obligados a validar los datos de entrada y, afortunadamente, MVC 3 viene acompañado de un sistema realmente potente para ayudarnos con esta crítica tarea. De hecho, es tan amplio que no es fácil conocerlo en toda su extensión.
Y lo que voy a intentar en esta charla es dar un repaso al sistema de validación de MVC 3 completo. De esta forma podréis conocer qué es lo que hay, lo que se puede hacer, y tener una idea de cómo hacerlo. Trataremos desde aspectos muy simples como las anotaciones incluidas en el framework, su personalización y extensión, hasta temas algo más avanzadillos como la creación de validadores en cliente o los proveedores de validación. Espero que me dé tiempo a todo, uuf!
Para poder seguirla creo que es conveniente (por no decir necesario) conocer ASP.NET MVC 3 (o 2) al menos a un nivel básico; no voy a tener tiempo para detenerme en ver qué es un controlador, cómo le llegan los parámetros a la acciones, o cómo se construye un formulario. Pero tampoco es que sean unos requisitos muy exigentes: cualquiera que haya jugado mínimamente con el framework creo que podrá entenderlo todo… o al menos ese es el objetivo.
Os recuerdo que se trata de un Webcast, o sea, que podéis asistir a este evento desde vuestro sillón favorito y con un saco de palomitas a la vera, y por supuesto es totalmente gratuito. Eso sí, debéis registraros previamente para poder asistir:
- Día: martes 27 de septiembre, 19:00 hora peninsular española (GMT+1)
- URL del registro: https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032494252&Culture=es-ES
Publicado por José M. Aguilar a las 12:16 p. m.
Etiquetas: aspnetmvc, auges, charlas, eventos, validadores
Hace tiempo traté el tema por aquí, y aporté una solución para la versión 2 de ASP.NET MVC, que aún utilizaba las bibliotecas de scripting de Microsoft Ajax. Sin embargo, la versión 3 ha sustituido “de serie” esos componentes por jQuery Validate y el magnífico sistema de validaciones no intrusivas, por lo que todo lo dicho en aquella ocasión no vale ya para nada :-(
El problema radica en que el plugin jQuery Validate utiliza únicamente el punto como separador de decimales, por lo que la validación en cliente de valores de tipo decimal, float o double que utilicen la coma finalizará siempre en un error e impedirá el envío del formulario, como puede observarse en la captura de pantalla de la derecha.
Por cierto, antes de que se me olvide, hace unos meses reportaron este asunto como bug en Microsoft Connect. Si el tema os preocupa, podéis ir y votarlo a ver si conseguimos que este asunto se tenga en cuenta en próximas revisiones.
Sin embargo, estrictamente hablando, no se trata de un bug de ASP.NET MVC, puesto que la validación en cliente ha sido delegada por completo al plugin de jQuery, y éste es el que no tiene en cuenta los aspectos de internacionalización. Desde este punto de vista, quizás tendría más sentido, por tanto, esta issue reportada en Github sobre jQuery Validate, que propone su integración de forma nativa con jQuery Global.
Por tanto, me temo que se trata de un asunto de responsabilidad compartida (y dispersa, por tanto) entre los equipos de MVC, de jQuery Validate, y no sé si de alguno más. Esperemos que entre todos puedan solucionar de forma razonable el problema.
En cualquier caso, los que ya estamos creando aplicaciones con MVC 3 no podemos esperar las soluciones oficiales, que seguro llegarán más tarde o más temprano, y nos vemos obligados a buscar alternativas que nos permitan convivir con este problema de la forma más cómoda posible.
Y esto es lo que veremos en este post: varias posibilidades que tenemos para que la validación en cliente de valores decimales no nos compliquen demasiado la vida. Seguro que hay más, seguro que las hay mejores, pero ahí van unas cuantas opciones que nos pueden ayudar en escenarios como el descrito anteriormente.
1. Desactivar la validación en cliente
Está claro que el problema es en cliente, por lo que si desactivamos estas validaciones y dejamos que sea el servidor el que se encargue de comprobar que los valores de los distintos campos cumplen las restricciones impuestas por su tipo y las anotaciones de datos, ya no nos afectará más la absoluta indiferencia de jQuery Validate hacia las particularidades culturales.Esto podemos conseguirlo de varias formas:
- desactivar la validación en cliente de forma global, estableciendo a
false
la propiedadclientValidationEnabled
en el web.config, lo cual dejará a toda la aplicación sin validaciones en cliente. Como solución es algo drástica, pero poderse se puede. - desactivar la validación en cliente de forma local, sólo en aquellos formularios en los que existan propiedades de tipo decimal, introduciendo el siguiente código Razor (o su correspondiente en ASPX) antes de la llamada a
BeginForm()
:@{ Html.EnableClientValidation(false); }
- desactivar la validación en cliente sólo en el campo que nos interese, que podemos conseguir introduciendo el siguiente script, imaginando que el campo decimal en el que queremos anular la validación en cliente tiene como identificador “Altura”:
<script type="text/javascript"> $("#Altura").removeAttr("data-val"); </script>
2. Modificar jQuery Validate
Esta es una solución algo bestia que he encontrado por ahí, pero soluciona el problema de un plumazo: modificar el código de jQuery Validate para que acepte comas en lugar de puntos para separar los dígitos decimales de los enteros tanto en la validación numérica como en los rangos.En el blog de Lenard Gunda podéis encontrar de forma muy detallada los cambios a realizar al archivo jquery.validate.js (o a su versión minimizada). Hay, sin embargo, un par de detalles que debemos tener en cuenta si optamos por esta solución:
- primero, que nos estamos separando de la distribución oficial del plugin. Si actualizamos la biblioteca jquery.validate, por ejemplo utilizando Nuget, volveremos a tenerlo todo como al principio, y tendremos que volver a introducir los cambios oportunos.
- segundo, que esto no nos ayudará en aplicaciones adaptadas a varios idiomas; si modificamos el plugin para que acepte comas como separador, ya no volverá a aceptar el punto. Una solución rápida que se me ocurre para esto es tener dos versiones de la biblioteca (la original y la modificada), y referenciar desde la página la apropiada para la cultura actual.
3. Modificar la forma en que jQuery Validate parsea los decimales
Afortunadamente, el plugin de validación para jQuery es muy flexible, y permite introducir código personalizado para la validación de formato numérico y comprobación de rangos, lo que nos brinda la posibilidad de solucionar nuestro problema de forma muy limpia.El siguiente código sería una primera aproximación a la solución del problema. Como podéis observar, simplemente introducimos en
$.validator.methods.number
y $.validator.methods.range
las funciones que queremos utilizar para validar respectivamente los números y los rangos, reemplazando la coma por el punto antes de realizar la conversión con parseFloat()
:<script type="text/javascript">
$.validator.methods.number = function (value, element) {
value = floatValue(value);
return this.optional(element) || !isNaN(value);
}
$.validator.methods.range = function (value, element, param) {
value = floatValue(value);
return this.optional(element) || (value >= param[0] && value <= param[1]);
}
function floatValue(value) {
return parseFloat(value.replace(",", "."));
}
</script>
Si incluimos este script en la página cuando la cultura activa sea la nuestra (o cualquier otra que también utilice la coma para separar decimales), tendremos el problema solucionado.
Una fórmula más elegante y universal sería modificar la función
floatValue()
, y en lugar de reemplazar de forma manual los caracteres, utilizar el plugin Global para realizar la conversión a flotante según la cultura actual. Los detalles de esto, sin embargo, los dejo para otro post.En fin, que como habréis comprobado existen mil y un enfoques posibles para enfrentarnos al problema. Espero que las ideas que hemos ido comentando os sean de utilidad para implementar vuestras propias soluciones hasta que tengamos una vía “oficial” para conseguirlo.
Publicado en: Variable not found.
Publicado por José M. Aguilar a las 11:58 a. m.
Etiquetas: asp.net, aspnetmvc, desarrollo, jquery, localizacion, trucos, validadores
Cada vez que tengo que forzar la validación de los datos de un formulario Webforms mediante javascript me veo obligado a preguntarle a Google, ese que todo lo sabe, cómo era el nombre de la función. Cosas de la edad, supongo ;-)
Así que, a modo de auto-recordatorio y con la intención de que pueda ser útil a alguien más, ahí va: la función se llama Page_ClientValidate()
. Retorna “true” si, una vez evaluados todos los validadores de la página, el valor de los campos es correcto (al menos en cliente; otra cosa son las comprobaciones en servidor, p.e., las definidas en un CustomValidator
).
Y como ejemplo de uso, puede valer el siguiente. Se trata de un botón de envío en un formulario donde se compone un correo electrónico:
1: ...
2: <asp:Button ID="btnEnviar" runat="server" Text="Enviar mail"
3: OnClick="btnEnviar_Click"
4: OnClientClick="return confirmar();"
5: />
6: ...
7:
8: <script type="text/javascript">
9: function confirmar() {
10: if (!Page_ClientValidate()) // Fuerza la validación en cliente
11: return false;
12:
13: return confirm('¿Seguro que desea realizar el envío?');
14: }
15: </script>
Como se puede observar, en el atributo OnClientClick
del botón incluye un script en el que se retorna el valor devuelto por la función confirmar
. Si el retorno es false, se cancela el Postback, evitando así que se invoque al evento btnEnviar_Click
que es el que realiza el envío del mail propiamente dicho.
En el cuerpo de la función confirmar()
, en primer lugar, validamos la página; si ésta no supera el proceso, los validadores habrán mostrado sus mensajes de error y retornamos falso, haciendo que se anule el postback. Si la validación es correcta, solicitamos al usuario que confirme la acción y retornamos su decisión.
Publicado en: Variable not found.
Publicado por José M. Aguilar a las 11:40 p. m.
Etiquetas: .net, asp.net, desarrollo, nivel básico, trucos, validadores, web
"Al utilizar la funcion ValidatorEnable para habilitar un validador, me activa automaticamente la validacion, y me muestra el texto que pongo para cuando la validacion no se cumpla, como puedo evitar esto"
Recordemos que el post trataba sobre cómo conseguir, desde Javascript, habilitar o deshabilitar validadores de controles incluidos en un webform utilizando la función
ValidatorEnable()
, que pone a nuestra disposición ASP.Net.El problema, como comenta Pablo, es que al habilitar la validación desde script se muestran de forma automática los mensajes de error en todos aquellos controles que no sean válidos, provocando un efecto que puede resultar desconcertante para el usuario.
Indagando un poco, he comprobado que el problema se debe a que
ValidatorEnable()
, después de habilitar el validator, comprueba si los valores del control son correctos, mostrando el error en caso contrario.Existen al menos dos formas de solucionar este problema.
La primera consiste en jugar con la visibilidad del mensaje de error. Como se observa en el siguiente código, al llamar a la función
HabilitaValidador()
, ésta llamará a ValidatorEnable
y acto seguido, si el control no es válido, oculta el mensaje de error:
function HabilitaValidador(validator, habilitar)
{
ValidatorEnable(validator, habilitar);
if (habilitar && !validator.isvalid)
validator.style.visibility = "hidden";
}
La segunda forma consiste en simular el comportamiento interno de
ValidatorEnable
, pero eliminando la llamada a la comprobación de la validez del control.
function HabilitaValidador(validator, habilitar)
{
validator.enabled = habilitar;
}
Como se puede ver, simplemente se está estableciendo la propiedad
enabled
del validador, sin realizar ninguna comprobación posterior.En ambos casos, la forma de utilizar esta función desde script sería la misma:
function activar()
{
HabilitaValidador("<%= RequiredFieldValidator1.ClientID %>", true);
}
Para mi gusto la opción más limpia, aunque sea jugando con la visibilidad de los elementos, es la primera de las mostradas, pues se respeta el ciclo completo de validación. En el segundo método nos estamos saltando las validaciones y el seguimiento de la validez global de la página, que la función original
ValidatorEnable
sí contempla.Espero que esto resuelva la duda.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 6:15 p. m.
Etiquetas: asp.net, consultas, javascript, trucos, validadores