VueJS

Validar formularios en Vue con Vee Validate

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:

Validación de formularios con Vue.js, VeeValidate y Bootstrap

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.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.