En proyectos reales recomiendo que te hagas tus servicios/directivas para evitar tanta repetición.
En los temas anteriores hemos visto cómo añadir las validaciones y cómo saber desde JavaScript las validaciones que han fallado. Ahora toca la parte de mostrar al usuario los mensajes de error.
La forma de mostrar los mensajes es bastante sencilla e ingeniosa. Lo que hacemos es poner todos los mensajes que necesitemos debajo de cada <input>
o donde quieras que aparezcan y luego con la directiva ng-show
los muestras. Veamos un ejemplo.
Nombre:<input type="text" ng-model="model.nombre" name="nombre" ng-maxlength="50" ng-minlength="3" ng-required="requeridoNombre" ng-pattern="patternNombre" > <span ng-show="miFormulario.nombre.$error.maxlength">El tamaño máximo debe ser 50</span>
miFormulario.nombre.$error.maxlength==true
y éso sólo ocurre si realmente el valor tiene un tamaño mayor que 50.
Si aplicamos este mismo patrón a la validación de required
veremos que tiene un problema:
Nombre:<input type="text" ng-model="model.nombre" name="nombre" ng-maxlength="50" ng-minlength="3" ng-required="requeridoNombre" ng-pattern="patternNombre" > <span ng-show="miFormulario.nombre.$error.maxlength">El tamaño máximo debe ser 50</span> <span ng-show="miFormulario.nombre.$error.required">El campo es requerido</span>
Queda un poco feo mostrar un mensaje de error cuando aún no ha empezado ni a escribir nada , por eso para ese tipo de validaciones se suele añadir la condición && miFormulario.nombre.$dirty
. Es decir que el usuario haya escrito por lo menos algo en ese campo.
Nombre:<input type="text" ng-model="model.nombre" name="nombre" ng-maxlength="50" ng-minlength="3" ng-required="requeridoNombre" ng-pattern="patternNombre" > <span ng-show="miFormulario.nombre.$error.maxlength">El tamaño máximo debe ser 50</span> <span ng-show="miFormulario.nombre.$error.required && miFormulario.nombre.$dirty">El campo es requerido</span>
Lo siguiente es añadir el resto de mensajes a todos los campos.
Pero si 8 campos son requeridos , deberemos escribir 8 veces cosas similares a :
<span ng-show="miFormulario.MI_CAMPO.$error.required && miFormulario.MI_CAMPO.$dirty">El campo es requerido</span>Siendo “MI_CAMPO” el nombre de cada uno de los 8 campos.
¿No es realmente una mala práctica hacer ésto?
Luego hay otro problema, ¿como era el mensaje del tamaño máximo? Era: “El tamaño máximo debe ser 50”.
Si nos fijamos hemos puesto “a piñon” el valor de 50. Seguro que tarde o temprano el atributo ng-maxlength
lo cambiaremos a otro valor , por ejemplo 40, y no nos damos cuenta de cambiar el mensaje.
¿No debería poder sacarse ese 50 del valor del atributo ng-maxlength
?
En Java en JSR 303: Bean Validation si que se hacen cosas así y están resueltos los 2 problemas. ¿Porque no lo están en AngularJS de forma estándar?
Si alguien cree que estoy equivocado en mi planteamiento estaría encantado de conocer sus argumentos
Lo normal en cualquier formulario es tener un botón para enviar los datos. Hay otro patrón que suele usarse en este caso y que es deshabilitar el botón hasta que el formulario sea válido. Por suerte es tan sencillo como:
<button ng-click="enviar()" ng-disabled="miFormulario.$invalid" >Enviar</button>
miFormulario.$invalid===true
.Vemos que de forma simple evitamos que se envíen datos sin validar en el cliente.
A esto hay que añadir otra cosa en la función enviar()
de JavaScript.
$scope.enviar=function() { if ($scope.miFormulario.$valid) { alert("Los datos aqui se habrían enviado al servidor y estarían validados en la parte cliente"); }else { alert("Hay datos inválidos"); } }
¿Porque comprobarlo en la función de enviar()
? Porque quizás acabemos poniendo en el interfaz de usuario alguna otra forma de llamar a enviar()
y se nos olvida comprobar en ese nuevo interfaz de usuario si el formulario es válido . Así que mejor comprobarlo siempre justo en el último sitio antes de enviar los datos, que es la función enviar()
.
Hay mas patrones en los formularios como que solo aparezcan los mensajes al pulsar el botón de enviar o solo al dejar el campo, sin embargo no los vamos a ver en este curso.
Por último nos queda ver como aplicar estilos CSS distintos en función de las validaciones. Es el típico caso de poner el campo en rojo si el estado es inválido.
Se podría hacer perfectamente con la directiva 4.10 ng-class que ya vimos, pero AngularJS no ofrece otra forma más sencilla.
Podemos definir 4 clases CSS que AngularJS aplicará automáticamente a los campos:
ng-valid
ng-invalid
ng-pristine
ng-dirty
Si definimos alguna de estas clases CSS, AngularJS las aplicará automáticamente a cualquier campo (<input>
, <select>
, etc) cuando dichos campos estén en el estado correspondiente al estilo CSS.
Es decir que si definimos el siguiente estilo:
.ng-invalid { border-color: red; }
En cuanto un campo esté en estado $invalid===true
, AngularJS le aplicará el estilo CSS de ng-invalid
y lo mismo con el resto de estilos.