Vee Validate es un plugin de Vue.js que sirve para validar formularios de una manera fácil pero poderosa.
Lo que destaca es:
- Su simplicidad, pues no se tiene que estudiar demasiado para comenzar a usarlo
- La flexibilidad que ofrece
- Soporte para otros idiomas (entre ellos el español)
- Mensajes de error predefinidos
- Simple sintaxis y validadores por defecto
- Reglas personalizadas
- Manejo del evento que desencadena la validación
En este artículo vamos a dar un repaso y explicación de VeeValidate con algunos ejemplos.
Al final tendremos un ejemplo completo que es como en la imagen:
Instalar VeeValidate con webpack
Si lo quieres hacer con Webpack asegúrate de contar con NPM y Node instalado, después de eso ejecuta:
npm install --save vee-validate
En tu archivo donde cargues Vue carga a VeeValidate e indica que Vue lo va a utilizar, de manera que quede como el siguiente código:
import Vue from 'vue'
import VeeValidate from "vee-validate";
Vue.use(VeeValidate);
VeeValidate sin webpack
Carga el script de VeeValidate después del de Vue en el HTML:
<script src="https://unpkg.com/vue@2.6.10/dist/vue.min.js"></script>
<script src="https://unpkg.com/vee-validate@latest"></script>
En tu script indica a Vue que lo tome en cuenta:
Vue.use(VeeValidate)
No necesitas importar nada porque al no usar Webpack el objeto de VeeValidate se registra globalmente.
Cargar más idiomas con VeeValidate
VeeValidate viene con muchos idiomas preinstalados. Para cargar un idioma (en este caso lo haré con el idioma español) hay que cargar el script del mismo. Los idiomas están aquí.
Si usas Webpack importa el idioma, así como el validador, e indica al Validador que utilice el idioma, así:
import Vue from 'vue'
import es from 'vee-validate/dist/locale/es'
// Importa VeeValidate y el Validator
import VeeValidate, { Validator } from "vee-validate";
Vue.use(VeeValidate);
// Indicar uso de idioma español
Validator.localize("es", es);
En caso de que no uses WebPack, carga también el script del idioma:
<script src="https://unpkg.com/vue@2.6.10/dist/vue.min.js">
</script>
<script src="https://unpkg.com/vee-validate@2.2.9/dist/vee-validate.js">
</script>
<script src="https://unpkg.com/vee-validate@2.2.9/dist/locale/es.js">
</script>
Y luego indica que se usará el idioma español. El trabajo es menos porque el idioma igualmente se registra de manera automática:
VeeValidate.Validator.localize("es");
Nota: recomiendo siempre cargar la misma versión del idioma y de VeeValidate como en el ejemplo, que cargo la versión 2.2.9 de ambas cosas.
Primer validación con VeeValidate
Dentro del componente que vamos a usar, en el input, agregamos un:
v-validate="'un_validador|otro_validador'"
Es importante poner las reglas entre comillas dentro de las comillas, recuerda que estamos pasándole un string, aunque podríamos pasar una string definido desde el código JavaScript.
La lista de validadores está aquí. Un ejemplo para que un dato sea obligatorio es:
<input name="nombre" v-validate="'required'" v-model="usuario.nombre" />
Puedes agregar múltiples reglas, separadas con un pipe |
.
Más validaciones
Para hacer que el valor sea un número obligatorio y mayor o igual que 18:
<input name="edad" v-validate="'required|numeric|min_value:18'"/>
Estamos indicando 3 validaciones: que sea obligatorio, que sea numérico y que el valor mínimo que puede tener es 18. En este caso, 18 es el argumento que recibe el validador min_value
.
Por cierto, si hay validadores que aceptan más argumentos, los mismos se pasan separados por comas.
Listar errores
VeeValidate va a crear una variable dentro de nuestro componente, llamada errors
. Esta variable tendrá toda la información de los errores que tenga nuestro formulario.
En el ejemplo anterior le pusimos un name
al input
, esto servirá más tarde al mostrar los errores.
Si quieres mostrar el error de ese input, haz esto:
{{errors.first('nombre')}}
En este caso, nombre
es el nombre del input.
Para mostrar todos los errores (por ejemplo, en un div al final del formulario) llama a errors.all()
e itera sobre ellos.
En el siguiente ejemplo muestro cómo hacerlo en un div con una lista:
<div v-show="errors.all().length" >
<ul>
<li v-for="(error, i) in errors.all()">{{error}}</li>
</ul>
</div>
El div se muestra si hay errores, si no, se oculta. Dentro del div se muestra una lista de los errores usando un v-for
.
Eventos que desencadenan la validación
Se puede controlar el momento en que la validación se hace. Por ejemplo, tal vez quieras hacerla en el evento blur, o tal vez en change.
De hecho se puede validar en muchos eventos. Para ello, al indicarle a Vue el uso de VeeValidate pasa un objeto de opciones:
Vue.use(VeeValidate, {
// Podría ser blur, change, etcétera. Si está vacío
// entonces se tiene que validar manualmente
events: "change|blur|keyup",
});
Yo estoy desencadenando la validación en 3 eventos: change, blur y keyup.
Igualmente se usa el pipe para separarlos, y puede ser un único evento.
Si tú quieres llamar a la validación manualmente, no indiques eventos, es decir, deja la cadena vacía.
Cómo saber si el formulario es válido
Los errores de validación se van a mostrar al usuario, pero eso no le va a impedir hacer la acción, ya que hasta ahora no había una manera de saber, desde el código, si el formulario era válido.
VeeValidete incorpora el método validate dentro de $validator
, el cual devuelve una promesa y al resolverse trae un booleano
.
El código se explica mejor:
this.$validator.validate()
.then(esValido => {
if (esValido) {
alert("OK, se envía el formulario ;)")
} else {
// Hacer algo aquí
}
});
Además de indicar si el formulario es válido, VeeValidate lo validará y mostrará errores al usuario, así que si en la sección anterior desactivaste la validación, al hacer esta acción se desencadena y se muestran los errores.
Validaciones personalizadas
VeeValidate es extensible y permite agregar validaciones propias, definidas por nosotros. Para ello, importamos de nuevo a Validator
e invocamos a extend
.
La función extend
recibe un objeto con dos funciones: getMessage
y validate
.
La función getMessage
debe devolver un mensaje que será mostrado en caso de que validate
regrese falso. Recibe dos argumentos: el nombre del campo y los argumentos que pasamos al indicar el validador. Los argumentos son un arreglo, que puede estar vacío si no hay argumentos.
La función validate
debe devolver un booleano indicando si la validación es correcta. Recibe el valor que tiene el input y los argumentos que pasamos al validador igualmente como arreglo.
Si no sabes qué son los argumentos del validador, en el ejemplo de min_value
, 18 era un argumento.
Veamos el siguiente ejemplo que prohíbe que determinado valor tenga algunas palabras. No te fijes en el algoritmo de la función, ni en la optimización del mismo, fíjate en la forma.
Nota: si usas WebPack tendrías que importar y acceder Validator
directamente, no VeeValidate.Validator
, en el ejemplo lo hago de esta manera porque no uso WebPack:
VeeValidate.Validator.extend('prohibirPalabras', {
getMessage: (campo, argumentos) => {
// argumentos es un arreglo
return "El campo " + campo + " no puede contener las siguientes palabras: " + argumentos.join(" ");
},
validate: (valor, argumentos) => {
return argumentos.every(argumento => !valor.includes(argumento))
},
});
Para usarlo en el HTML se indica así:
<textarea v-validate="'required|prohibirPalabras:foo,bar,baz'" name="biografia"></textarea>
Fue en un textarea
pero funciona igualmente para un input
.
Clases y estilos de validación
En ocasiones hay frameworks CSS (o nuestros estilos lo soportan) para mostrar el input con determinado color para indicar que es válido o inválido.
Por ejemplo, en Bootstrap se usa la clase is-valid
para indicar que el input es válido, y la clase is-invalid
para lo contrario. Estas clases le dan un color verde y rojo respectivamente.
Podríamos agregar manualmente la clase así:
:class="{'is-valid':!errors.first('nombre'), 'is-invalid': errors.first('nombre')}"
Ya que si errors.first
devolviera algo, el valor sería true
(bueno, algo que JS considera como true
) y de lo contrario, false
. Así podríamos intercambiar las clases.
Pero, ¿para qué complicarnos, si VeeValidate puede hacerlo por nosotros? simplemente hay que especificar que use las clases, e indicar cuál usar cuando sea válido o inválido.
Vue.use(VeeValidate, {
classes: true,// Sí queremos que ponga clases automáticamente
// Indicar qué clase poner al input en caso de que sea
// válido o inválido. Usamos Bootstrap 4
classNames: {
valid: "is-valid",
invalid: "is-invalid",
}
});
Obviamente, si tus clases son distintas a “is-valid” e “is-invalid” simplemente indica su nombre.
Poniendo todo junto
He utilizado la plantilla de Bootstrap que publiqué hace algún tiempo. Gracias a los estilos de Bootstrap podemos hacer la validación más interactiva.
El código HTML queda así:
<!doctype html>
<html lang="es">
<!--
Demostrar la validación de VeeValidate
(plugin para Vue.js)
Plantilla inicial de Bootstrap 4
@author parzibyte
Visita: parzibyte.me/blog
-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Validación de formularios con VeeValidate">
<meta name="author" content="Parzibyte">
<title>Validación de formularios con VeeValidate</title>
<!-- Cargar el CSS de Boostrap-->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<main role="main" class="container">
<div class="row" id="app">
<!-- Aquí pon las col-x necesarias, comienza tu contenido, etcétera -->
<div class="col-12">
<h1>Validación de formularios con VeeValidate</h1>
<a target="_blank" href="//parzibyte.me/blog">By Parzibyte</a>
<div class="form-group">
<input name="nombre" autocomplete="off" class="form-control" v-validate="'required'" v-model="usuario.nombre" type="text" placeholder="Nombre completo" />
<div class="invalid-feedback">
{{errors.first('nombre')}}
</div>
</div>
<div class="form-group">
<input name="edad" autocomplete="off" class="form-control" v-validate="'required|numeric|min_value:18'" v-model.number="usuario.edad" type="text" placeholder="Edad" />
<div class="invalid-feedback">
{{errors.first('edad')}}
</div>
</div>
<div class="form-group">
<input name="correo" autocomplete="off" class="form-control" v-validate="'required|email'" v-model.number="usuario.correo" type="email" placeholder="Correo electrónico" />
<div class="invalid-feedback">
{{errors.first('correo')}}
</div>
</div>
<div class="form-group">
<textarea class="form-control" v-validate="'required|prohibirPalabras:foo,bar,baz'" placeholder="Biografía" v-model="usuario.biografia" name="biografia" cols="20" rows="5"></textarea>
<div class="invalid-feedback">
{{errors.first('biografia')}}
</div>
</div>
<div v-show="errors.all().length" class="alert alert-danger">
<ul>
<li v-for="(error, i) in errors.all()">{{error}}</li>
</ul>
</div>
<button class="btn btn-success mb-5" @click="intentarEnviar">Enviar</button>
</div>
</div>
</main>
<script src="https://unpkg.com/vue@2.6.10/dist/vue.min.js">
</script>
<script src="https://unpkg.com/vee-validate@2.2.9/dist/vee-validate.js">
</script>
<script src="https://unpkg.com/vee-validate@2.2.9/dist/locale/es.js">
</script>
<script src="script.js"></script>
</body>
</html>
Y el script así:
Vue.use(VeeValidate, {
classes: true,// Sí queremos que ponga clases automáticamente
// Indicar qué clase poner al input en caso de que sea
// válido o inválido. Usamos Bootstrap 4
classNames: {
valid: "is-valid",
invalid: "is-invalid",
},
// Podría ser blur, change, etcétera. Si está vacío
// entonces se tiene que validar manualmente
events: "change|blur|keyup",
});
VeeValidate.Validator.localize("es");
VeeValidate.Validator.extend('prohibirPalabras', {
getMessage: (campo, argumentos) => {
// argumentos es un arreglo
return "El campo " + campo + " no puede contener las siguientes palabras: " + argumentos.join(" ");
},
validate: (valor, argumentos) => {
return argumentos.every(argumento => !valor.includes(argumento))
},
})
new Vue({
el: "#app",
data: () => ({
usuario: {
nombre: null,
edad: null,
correo: null,
biografia: null,
}
}),
methods: {
intentarEnviar() {
this.$validator.validate()
.then(esValido => {
if (esValido) {
alert("OK, se envía el formulario ;)")
} else {
// Hacer algo aquí
}
});
}
}
});
Como conclusión dejo un enlace a la documentación oficial y uno al repositorio en GitHub en donde encontrarás todavía más cosas muy interesantes sobre VeeValidate.