Índice:
En este tema vamos a ver cómo realizar una de las acciones principales de Javascript que es la validación de formularios en el lado cliente.
Se trata de una verificación útil porque evita enviar datos al servidor que sabemos que no son válidos pero NUNCA puede sustituir a la validación en el lado servidor ya que en el lado cliente se puede manipular el código desde la consola para que se salte las validaciones que le pongamos.
Podéis encontrar una guía muy completa de validación de formularios en el lado cliente el la página de MDN web docs que ha servido como base para estos apuntes.
Además, al final de este tema, veremos una pequeña introducción a las expresiones regulares en Javascript.
Básicamente tenemos 2 maneras de validar un formulario en el lado cliente:
La ventaja de la primera opción es que no tenemos que escribir código sino simplemente poner unos atributos a los INPUT que indiquen qué se ha de validar. La principal desventaja es que no tenemos ningún control sobre el proceso, lo que provocará cosas como:
Funciona añadiendo atributos a los campos del formulario que queremos validar. Los más usados son:
pattern="^[0-9]{5}$"
También producen errores de validación si el contenido de un campo no se adapta al type indicado (email, number, …) o si el valor de un campo numérico no cumple con el step indicado.
Cuando el contenido de un campo es valido dicho campo obtiene automáticamente la pseudoclase :valid y si no lo es tendrá la pseudoclase :invalid lo que nos permite poner reglas en nuestro CSS para destacar dichos campos, por ejemplo:
input:invalid {
border: 2px dashed red;
}
Además de las anteriores tenemos las pseudoclases :required, :optional, que nos permiten poner reglas de estilo a los campos obligatorios o no, y :focus para el campo con el foco.
La validación del navegador se realiza al enviar el formulario. Si encuentra un error lo muestra, se detiene la validación del resto de campos y no se envía el formulario.
Mediante Javscript tenemos acceso a todos los campos del formulario por lo que podemos hacer la validación como queramos, pero es una tarea pesada, repetitiva y que provoca código spaguetti difícil de leer y mantener más adelante.
Para hacerla más simple podemos usar la API de validación de formularios de HTML5 que permite que sea el navegador quien se encargue de comprobar la validez de cada campo pero las acciones (mostrar mensajes de error, no enviar el formulario, …) las realizamos desde Javascript.
Esto nos da la ventaja de:
Las principales propiedades y métodos que nos proporciona esta API son:
setCustomValidity('')
En la página de W3Schools podéis ver algún ejemplo básico de esto. También a continuación tenéis un ejemplo simple del valor de las diferentes propiedades involucradas en la validación de un campo de texto que es obligatorio y cuyo tamaño debe estar entre 5 y 50 caracteres:
Para validar un formulario nosotros pero usando esta API debemos añadir a la etiqueta <form> el atributo novalidate
que hace que no se encargue el navegador de mostrar los mensajes de error ni de decidir si se envía o no el formulario (aunque sí valida los campos) sino que lo haremos nosotros.
Un ejemplo sencillo de validación de un formulario podría ser:
<form novalidate>
<label for="nombre">Por favor, introduzca su nombre (entre 5 y 50 caracteres): </span>
<input type="text" id="nombre" name="nombre" required minlength="5" maxlength="50">
<span class="error"></label>
<br />
<label for="mail">Por favor, introduzca una dirección de correo electrónico: </label>
<input type="email" id="mail" name="mail" required minlength="8">
<span class="error"></span>
<button type="submit">Enviar</button>
</form>
const form = document.getElementsByTagName('form')[0];
const nombre = document.getElementById('nombre');
const nombreError = document.querySelector('#nombre + span.error');
const email = document.getElementById('mail');
const emailError = document.querySelector('#mail + span.error');
form.addEventListener('submit', (event) => {
if(!form.checkValidity()) {
event.preventDefault();
}
nombreError.textContent = nombre.validationMessage;
emailError.textContent = email.validationMessage;
});
.error {
color: red;
}
input:invalid {
border: 2px dashed red;
}
Estamos usando
validationMessage
para mostrar el posible error de cada campo, o quitar el error cuando el campo sea válidocheckValidity()
para no enviar/procesar el formulario si contiene erroresSi no nos gusta el mensaje del navegador y queremos personalizarlo podemos hacer una función que reciba un <input> y usando su propiedad validity
devuelva un mensaje en función del error detectado:
function customErrorValidationMessage(input) {
if (input.checkValidity()) {
return ''
}
if (input.validity.valueMissing) {
return 'Este campo es obligatorio'
}
if (input.validity.tooShort) {
return `Debe tener al menos ${input.minLength} caracteres`
}
// Y seguiremos comprobando cada atributo que hayamos usado en el HTML
return 'Error en el campo' // por si se nos ha olvidado comprobar algo
}
Y ahora en vez de nombreError.textContent = nombre.validationMessage
haremos nombreError.textContent = customErrorValidationMessage(nombre)
.
Si tenemos que validar algo que no puede hacerse mediante atributos HTML (por ejemplo si el nombre de usuario ya está en uso) deberemos hacer la validación “a mano” y en caso de no ser válido ponerle un error con .setCustomValidity()
, pero debemos recordar quitar el error si todo es correcto o el formulario siempre será inválido. Modificando el ejemplo:
const nombre = document.getElementById('nombre');
const nombreError = document.querySelector('#nombre + span.error');
form.addEventListener('submit', (event) => {
if (nombreEnUso(nombre.value)) {
nombre.setCustomValidity('Ese nombre de usuario ya está en uso')
} else {
nombre.setCustomValidity('') // Se quita el error personalizado
}
if(!form.checkValidity()) {
...
}
})
Hay infinidad de páginas donde poder consultar cómo validar ficheros e imágenes en un formulario. Os recomiendo:
Existen múltiples librerías que facilitan enormenmente el tedioso trabajo de validar un formulario. Un ejemplo es yup.
Las expresiones regulares permiten buscar un patrón dado en una cadena de texto. Se usan mucho a la hora de validar formularios o para buscar y reemplazar texto. En Javascript se crean poniéndolas entre caracteres /
(o instanciándolas de la clase RegExp, aunque es mejor de la otra forma):
let cadena='Hola mundo';
let expr=/mundo/;
expr.test(cadena); // devuelve true porque en la cadena se encuentra la expresión 'mundo'
La potencia de las expresiones regulares es que podemos usar patrones para construir la expresión. Los más comunes son:
[abc]
: cualquier carácter de los indicados (‘a’ o ‘b’ o ‘c’)[^abc]
: cualquiera excepto los indicados[a-z]
: cualquier minúscula (el carácter ‘-‘ indica el rango entre ‘a’ y ‘z’, incluidas)[a-zA-Z]
: cualquier letra( | )
(pipe): debe coincidir con una de las opciones indocadas:
(x|y)
: la letra x o la y (sería equivalente a [xy]
(http|https)
: cualquiera de las 2 palabras.
(punto): un único carácter, sea el que sea\d
: un dígito (\D
: cualquier cosa menos dígito)\s
: espacio en blanco (\S
: lo opuesto)\w
: una palabra o carácter alfanumérico (\W
lo contrario)\b
: delimitador de palabra (espacio, ppio, fin)\n
: nueva línea+
: al menos 1 vez (ej. [0-9]+
al menos un dígito)*
: 0 o más veces?
: 0 o 1 vez{n}
: n caracteres (ej. [0-9]{5}
= 5 dígitos){n,}
: n o más caracteres{n,m}
: entre n y m caracteres^
: al ppio de la cadena (ej.: ^[a-zA-Z]
= empieza por letra)$
: al final de la cadena (ej.: [0-9]$
= que acabe en dígito)/i
: que no distinga entre Maysc y minsc (Ej. /html/i
= buscará html, Html, HTML, …)/g
: búsqueda global, busca todas las coincidencias y no sólo la primera/m
: busca en más de 1 línea (para cadenas con saltos de línea)EJERCICIO: contruye una expresión regular para lo que se pide a continuación y pruébala con distintas cadenas:
- un código postal
- un NIF formado por 8 números, un guión y una letra mayúscula o minúscula
- un número de teléfono y aceptamos 2 formatos: XXX XX XX XX o XXX XXX XXX. EL primer número debe ser un 6, un 7, un 8 o un 9
Los usaremos para saber si la cadena coincide con determinada expresión o para buscar y reemplazar texto:
expr.test(cadena)
: devuelve true si la cadena coincide con la expresión. Con el modificador /g hará que cada vez que se llama busque desde la posición de la última coincidencia. Ejemplo:let str = "I am amazed in America";
let reg = /am/g;
console.log(reg.test(str)); // Imprime true
console.log(reg.test(str)); // Imprime true
console.log(reg.test(str)); // Imprime false, hay solo dos coincidencias
let reg2 = /am/gi; // ahora no distinguirá mayúsculas y minúsculas
console.log(reg.test(str)); // Imprime true
console.log(reg.test(str)); // Imprime true
console.log(reg.test(str)); // Imprime true. Ahora tenemos 3 coincidencias con este nuevo patrón
expr.exec(cadena)
: igual pero en vez de true o false devuelve un objeto con la coincidencia encontrada, su posición y la cadena completa:let str = "I am amazed in America";
let reg = /am/gi;
console.log(reg.exec(str)); // Imprime ["am", index: 2, input: "I am amazed in America"]
console.log(reg.exec(str)); // Imprime ["am", index: 5, input: "I am amazed in America"]
console.log(reg.exec(str)); // Imprime ["Am", index: 15, input: "I am amazed in America"]
console.log(reg.exec(str)); // Imprime null
cadena.match(expr)
: igual que exec pero se aplica a la cadena y se le pasa la expresión. Si ésta tiene el modificador /g devolverá un array con todas las coincidencis:let str = "I am amazed in America";
let reg = /am/gi;
console.log(str.match(reg)); // Imprime ["am", "am", "Am"}
cadena.search(expr)
: devuelve la posición donde se encuentra la coincidencia buscada o -1 si no aparececadena.replace(expr, cadena2)
: devuelve una nueva cadena xon las coincidncias de la cadena reemplazadas por la cedena pasada como 2º parámetro:let str = "I am amazed in America";
console.log(str.replace(/am/gi, "xx")); // Imprime "I xx xxazed in xxerica"
console.log(str.replace(/am/gi, function(match) {
return "-" + match.toUpperCase() + "-";
})); // Imprime "I -AM- -AM-azed in -AM-erica"
No vamos a profundizar más sobre las expresiones regulares. Es muy fácil encontrar por internet la que necesitemos en cada caso (para validar un e-mail, un NIF, un CP, …). Podemos aprender más en:
También, hay páginas que nos permiten probar expresiones regulares con cualquier texto, como regexr.