miércoles, 26 de octubre de 2011

jquery.validation o cómo validar tus formularios

Llevo mucho tiempo queriendo hincar el diente al plugin de jQuery, jquery.validation.

Como desarrollador de programas de gestión, el validar formularios es una tarea obligada y repetitiva. Siendo así quiero abandonar mis actuales métodos manuales de validación y adoptar una nueva mecánica de validación cuyo código sea más limpio, compacto y extensible.

Buscando en Internet, todas las pistas nos conducen a jquery.validation (curioso que después el fichero javascript se llame jquery.validate, pero bueno…). De hecho, incluso Microsoft y sus proyectos ASP.NET MVC3 delega las tareas de validación en este plugin en detrimento de sus propias librerías de scripting a las que ya no da soporte.

Cabe mencionar que la utilización de jquery.validation en proyectos de tipo ASP.NET WebForms se complica un poco por la capa de abstracción que agrega esta tecnología y la imposición de que cualquier página debe y sólo puede tener un formulario. Siendo así, los ejemplos de este post están plenamente enfocados a páginas web sin tener en cuenta el lado del servidor. Es decir, este post servirá a desarrolladores de ASP.NET, de PHP, etc. Todo ello porque nos quedamos en el lado cliente y no nos importa el lado del servidor.

Instalación

El primer e ineludible paso es descargar el plugin.

La página oficial es http://bassistance.de/jquery-plugins/jquery-plugin-validation/ que finalmente redirecciona a http://jqueryvalidation.org/

Si trabajas con Visual Studio puedes descargar el paquete a través de NuGet, que resulta más cómodo y además incluye las dependencias necesarias, que en nuestro caso es solamente la librería jQuery.

La documentación sobre el plugin está disponible en http://rocketsquared.com/wiki/Plugins/Validation

Para comenzar a utilizar jquery.validation, simplemente debemos agregar una referencia a las librerías jQuery y jquery.validation en nuestra página.

    <script src="Scripts/jquery-1.6.4.js" type="text/javascript"></script>

    <script src="Scripts/jquery.validate.js" type="text/javascript"></script>


Conceptos básicos

Si trabajamos con jquery.validation hay que tener claros que son los métodos de validación y las reglas de validación.

Los métodos de validación implementan el código necesario para validar un elemento.

De serie tenemos disponibles un número considerable de métodos de validación para las comprobaciones más habituales, pero siempre es posible agregar a jquery.validation nuestras propias validaciones personalizadas.

Por ejemplo, un método de validación sería el código necesario para validar que la entrada es numérica.

Por otro lado, las reglas de validación permiten asociar un elemento de nuestro formulario a uno o más métodos de validación.

Para asociar una regla de validación a un elemento, podemos hacerlo de las siguientes formas que no son excluyentes y pueden combinarse según nuestras necesidades:

  • A través de nombres de clases css en atributo class. Por ejemplo class=”required number” especifica que nuestro elemento será requerido y sólo aceptará números.
    • Por supuesto, estos nombres de clases no tienen por qué existir en tu hoja de estilos, son clases que utilizará sólo jquery.validation.
  • Con atributos personalizados que requieren parámetros. Por ejemplo <input type=”text” minlength=”3”>, especifica que el contenido de nuestra caja de texto no debería ser menor a 3 caracteres
  • A través de código javascript y añadiendo las reglas a través del objeto rules.

Un primer ejemplo

Con este primer ejemplo romperemos el hielo.

    <form method="post" id="myForm">

    <p>

        Nombre

        <input type="text" id="nombre" name="nombre" class="required" />

    </p>

    <p>

        Edad

        <input type="text" id="edad" name="edad" class="required digits" />

    </p>

    <p>

        <input type="submit" value="Enviar" />

    </p>

    </form>

    <script type="text/javascript">

        $().ready(function () {

$("#myForm").validate({ debug: true });

        });

    </script>


En este formulario cabe reseñar lo siguiente:

  • Hemos especificado las reglas de validación a través de nombres de clases.
  • Hemos llamado al método validate() para el elemento myForm, que configura el formulario para que sea validado.
    • Además hemos especificado que estamos en depuración para que el formulario no sea enviado. Lógicamente, en producción no tendremos activado este parámetro.
  • A partir de este momento, el formulario no podrá ser enviado si no cumple con nuestras reglas impuestas.

Si ampliamos el ejemplo anterior para que el nombre tenga al menos 2 caracteres y la edad esté comprendida entre 18 y 99 años, tendremos que especificar estas reglas de validación a través de atributos con parámetros:

<form method="post" id="myForm">

<p>

    Nombre

    <input type="text" id="nombre" name="nombre" class="required" minlength="2" />

</p>

<p>

    Edad

    <input type="text" id="edad" name="edad" class="required digits" min="18" max="99" />

</p>

<p>

    <input type="submit" value="Enviar" />

</p>

</form>


Si no nos gusta especificar las reglas de validación a través de nombres de clases o atributos con parámetros, podemos utilizar javascript para acceder al objeto rules y meterlas por código:

    <form method="post" id="myForm">

    <p>

        Nombre

        <input type="text" id="nombre" name="nombre" />

    </p>

    <p>

        Edad

        <input type="text" id="edad" name="edad" />

    </p>

    <p>

        <input type="submit" value="Enviar" />

    </p>

    </form>

    <script type="text/javascript">

        $().ready(function () {

            $("#myForm").validate({

                debug: true,

                rules: {

                    nombre: {

                        required: true,

                        minlength: 2

                    },

                    edad: {

                        required: true,

                        digits: true,

                        min: 18,

                        max: 99

                    }

                }

            });

        });

    </script>


Mensajes de error

Algo importante cuando validamos, es cómo y dónde se muestran los mensajes de error.

Cuando sucede un error durante la validación, por defecto jquery.validation agrega dinámicamente una etiqueta label a continuación del campo validado. Además, el mensaje de esta etiqueta es igualmente predefinido y está en inglés.

clip_image001

clip_image002

En lo relativo al nuevo elemento label creado, es posible especificar el tipo de elemento que queremos crear para mostrar un error, en qué lugar del documento queremos que aparezca, mostrar resúmenes de errores para agrupar los mensajes, etc.  Lo cierto es que el plugin jquery.validation es muy configurable y se puede hacer con él casi cualquier cosa.

En un punto siguiente en este mismo post, daré unas breves indicaciones de cómo personalizar este mensaje (digo breves porque si no este post sería infinito y lo que pretendo es que sea una introducción a jquery.validation).

Lo que sí me parece muy importante es la traducción del mensaje. Después de todo, de poco serviría este plugin si los mensajes fueran hardcode.

La forma más sencilla de traducir los mensajes es bajarse la traducción de los mismos al lenguaje que necesites. Por defecto, jquery.validation está traducido a más de 41 idiomas, pero si aun así tu idioma no está disponible te resultará bastante sencillo traducirlo.

En la misma descarga del plugin hay una carpeta localization donde están todos los ficheros de idioma.

Si por ejemplo, queremos los mensajes en español bastaría con incluir la siguiente referencia a nuestra página, siempre después de la referencia a jquery.validation.

<script src="Scripts/messages_es.js" type="text/javascript"></script>


El contenido de este fichero es el siguiente:

/*

 * Translated default messages for the jQuery validation plugin.

 * Locale: ES

 */

jQuery.extend(jQuery.validator.messages, {

  required: "Este campo es obligatorio.",

  remote: "Por favor, rellena este campo.",

  email: "Por favor, escribe una dirección de correo válida",

  url: "Por favor, escribe una URL válida.",

  date: "Por favor, escribe una fecha válida.",

  dateISO: "Por favor, escribe una fecha (ISO) válida.",

  number: "Por favor, escribe un número entero válido.",

  digits: "Por favor, escribe sólo dígitos.",

  creditcard: "Por favor, escribe un número de tarjeta válido.",

  equalTo: "Por favor, escribe el mismo valor de nuevo.",

  accept: "Por favor, escribe un valor con una extensión aceptada.",

  maxlength: jQuery.validator.format("Por favor, no escribas más de {0} caracteres."),

  minlength: jQuery.validator.format("Por favor, no escribas menos de {0} caracteres."),

  rangelength: jQuery.validator.format("Por favor, escribe un valor entre {0} y {1} caracteres."),

  range: jQuery.validator.format("Por favor, escribe un valor entre {0} y {1}."),

  max: jQuery.validator.format("Por favor, escribe un valor menor o igual a {0}."),

  min: jQuery.validator.format("Por favor, escribe un valor mayor o igual a {0}.")

});


Una vez hemos traducido los mensajes predefinidos, podríamos querer mostrar mensajes personalizados o simplemente un mensaje especial para un campo concreto.

jquery.validation resuelve la búsqueda del mensaje a mostrar de la siguiente forma:

·         Primero busca si hemos especificado un mensaje para nuestro elemento a través de javascript. Si lo encuentra, este será siempre el mensaje mostrado. Con javascript podemos especificar un único mensaje para todos los errores de validación o afinar un mensaje por cada tipo de error de validación.

·         Segundo busca si nuestro elemento tiene definido el atributo title. Si lo encuentra, el valor del mismo será mostrado.

·         Por último, si no encuentra mensajes desde javascript ni el atributo title, buscará en los mensajes predefinidos.

Un ejemplo de personalización a través de javascript:

        $().ready(function () {

            $("#myForm").validate({

                debug: true,

                rules: {

                    nombre: {

                        required: true,

                        minlength: 2

                    },

                    edad: {

                        required: true,

                        digits: true,

                        min: 18,

                        max: 99

                    }

                },

                messages: {

                    nombre: {

                        required: "Nombre es obligatorio",

                        minlength: function (p, element) {

                            return "Nombre tiene que ser igual o mayor que " + p;

                        }

                    },

                    edad: "Este será el único mensaje para edad"

                }

            });

        });

 

Reglas y métodos de validación personalizados

Si no tenemos suficiente con las reglas y métodos de validación que incluye de serie jquery.validation, resulte muy sencillo implementar nuestra propia lógica de validación.

Por ejemplo, crearemos un regla que validará si el nombre suministrado es empleado o no de nuestra empresa.

La regla de validación la llamaremos esempleado y al método de validación le llamaremos esEmpleadoEmpresa. En la práctica, el método de validación suele llamarse igual que la regla de validación, pero en este ejemplo las he llamado distintas para que veas que no es necesario asociar una regla y su método por nombre.

// 1. DEFINIR NUESTRO MÉTODO DE VALIDACIÓN PERSONALIZADO

 

function esEmpleadoInterno(value, element, param) {

    //value es el valor actual del elemento que se está validando

    //element es el elemento DOM que se está validando

    //param son los parámetros especificados por el método

    //  p. ej. en el caso de minlength="3", param será 3

    //  en caso de que el método no tenga parámetros, param será true

    value = value.toLowerCase();

    if (value == "sergio" || value == "antonio" || value == "dani") {

        return true; //supera la validación

    }

    else {

        return false; //error de validación

    }

}

 

// 2. REGISTRAR REGLA DE VALIDACIÓN, MÉTODO DE VALIDACIÓN Y MENSAJE POR DEFECTO

 

$.validator.addMethod("esempleado", esEmpleadoInterno, "No eres empleado");

 

// 3. UTILIZAR NUESTRA NUEVA REGLA DE VALIDACIÓN

 

$().ready(function () {

    $("#myForm").validate({

        rules: {

            nombre: {

                esempleado: true

            }

        }

    });

});

 

Remote

Lo cierto es que remote es muy sencillo de entender. Simplemente delegamos la validación de nuestro elemento en una llamada a una url (servicio web, método de página, controlador genérico, etc.) que validará el valor en el servidor y tiene que devolver en formato JSON un true si la validación ha tenido éxito o false (o cualquier otro valor distinto de true) en caso contrario.

En ASP.NET (sin importar si hablamos de WebForms o de MVC) podríamos agregar por ejemplo un controlador genérico (.ashx) para llevar a cabo la tarea de validación en el servidor.

<%@ WebHandler Language="VB" Class="Remote" %>

 

Imports System

Imports System.Web

 

Public Class EsSergio : Implements IHttpHandler

   

    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

        context.Response.ContentType = "application/json"

        Dim js As New System.Web.Script.Serialization.JavaScriptSerializer

        Dim nombre As String = context.Request.QueryString.Item("nombre")

        If nombre = "Sergio" Then

            context.Response.Write(js.Serialize(True))

        Else

            context.Response.Write(js.Serialize(False))

            'context.Response.Write(js.Serialize("No eres Sergio"))

        End If

    End Sub

 

    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable

        Get

            Return False

        End Get

    End Property

 

End Class


Y el código javascript para necesario sería:

            $("#myForm").validate({

                rules: {

                    nombre: {

                        remote: "EsSergio.ashx"

                    }

                }

            });


Por defecto, remote hace una petición GET con los parámetros nombre=valor.

En cualquier caso, remote permite configurar todo lo que queremos la petición AJAX a través de su parámetro options.

Personalizando la validación

En este punto veremos opciones de personalización de jquery.validator que nos pueden ayudar a mejorar tanto nuestra experiencia como desarrolladores como la experiencia del usuario (muchas de estas opciones se pueden configurar tanto en setDefaults, en validate para la primera vez que configuramos el formulario como en siguientes llamadas a validate – accediendo después a settings – para modificar algo de un formulario ya configurado).

No pretendo poner un ejemplo sobre cada caso concreto, sino simplemente que sepas que se pueden hacer ciertas cosas y que sepas por dónde van los tiros.

submitHandler nos permite especificar una función que se llamará cuando la validación haya tenido éxito. En este función podemos incluir código de validación a nivel global y además será responsabilidad nuestra enviar definitivamente el formulario con form.submit().

invalidHandler es una función que se llamará si la validación no ha tenido éxito.

Con ignore podemos especificar un selector jQuery para ignorar campos de nuestro formulario.

onsubmit, onfocus, onkeyup, onclick nos permiten decidir cuándo se realizará la validación.

Con errorClass y validClass podemos especificar el nombre de la clase CSS que se agregará al elemento validado en caso de fracaso o de éxito de la validación.

Con errorElement, errorContainer, errorLabelContainer y wrapper podemos configurar la posición y que tipo de elementos se generarán para los mensajes de error.

showErrors es una función que nos permite tratar con todos los mensajes de errores encontrados para visualizar de una forma concreta o realizar la operación que creamos oportuna.

errorPlacement es una función que nos permite decidir donde situar los mensajes de error generados.

higlight y unhiglight determinan como resaltar los elementos que no han superado la validación.

Está claro que jquery.validation da para muchos posts, pero en mi caso hasta aquí ha llegado mi introducción a jquery.validation.

Espero que este post te haya servido al menos para que te pique el gusanillo y a partir de ahora valides mejor y de forma más mecánica tus formularios.

Un saludo!