Validación de formularios Web con JavaScript

13/08/2024 | HTML, JavaScript, Seguridad | 0 comentarios

Este artículo te muestra cómo usar JavaScript para validar formularios web, asegurando datos seguros y mejorando la experiencia del usuario.

Descargar archivos Ver ejemplo


La validación de formularios web es indispensable desarrollo de aplicaciones web, asegura que los datos ingresados por los usuarios cumplen con los requisitos esperados antes de ser enviados al servidor. Exploremos cómo validar formularios web utilizando JavaScript.

Validación básica

Lo primero es crear el formulario que deseamos validar.


<form id="formRegister">
  <label for="name">Nombre:</label>
  <input type="text" id="name" name="name" required>

  <label for="email">Email:</label>
  <input type="email" id="email" name="email" required>

  <label for="phone">Teléfono:</label>
  <input type="number" id="phone" name="phone">

  <div class="messages"> </div>
  <button type="submit">Enviar</button>
</form>

Creamos los estilos para este formulario: para todos los campos input creamos los estilos para el estado normal, para el focus y cuando hay error.


/* form styles */
form input { display: block; font-size: 0.84em; border: solid 2px #ccc; }
form input:focus { border:2px solid rgba(0,0,0,.4); }
form input.error { border:2px solid #dd356e; }
/* messages style */
form .messages { color: #dd356e; background-color: rgba(212, 63, 58, 0.25); display: none; }
form .messages.show { display: block; }

Luego creamos un script que valide el formulario, para ello detectamos el evento submit que es cuando el usuario quiere enviar el formulario y validamos uno a uno los campos del formulario, si existe un error le agregamos el estilo error y al final mostramos todos los mensajes de error.


document.addEventListener('DOMContentLoaded', function () {
    const $form = document.getElementById('formRegister');
    const $name = document.getElementById('name');
    const $email = document.getElementById('email');
    const $phone = document.getElementById('phone');
    const $messages = $form.querySelector('.messages');

    $form.addEventListener('submit', function (event) {
        event.preventDefault();

        // Obtener valores de los campos
        let name = $name.value.trim();
        let email = $email.value.trim();
        let phone = $phone.value.trim();
        let errors = [];

        // Validación del nombre
        if (name.length > 0) {
            $name.classList.remove('error');
        } else {
            errors.push('El nombre debe tener al menos 3 caracteres.');
            $name.classList.add('error');
        }

        // Validación del email
        if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
            $email.classList.remove('error');
        } else {
            errors.push('El email no es válido.');
            $email.classList.add('error');
        }

        // Validación del teléfono
        if (/^\d+$/.test(phone) && phone.length === 9) {
            $phone.classList.remove('error');
        } else {
            errors.push('El teléfono es requerido y de 9 dígitos');
            $phone.classList.add('error');
        }

        // Mostrar mensajes de error o enviar el formulario
        if (errors.length > 0) {
            $messages.innerHTML = errors.join('
'); $messages.classList.add('show'); } else { $messages.classList.add('remove'); $form.submit(); } }); });

El resultado del ejemplo se puede visualizar en validation-basic.html.

Validación Mejorada

Podemos generalizar la validación, para ello vamos a agregar atributos al formulario que permita definir el tipo de validación que se debe aplicar: data-validate para definir el tipo de validación y data-message para el mensaje de error.


<form id="formRegister">
  <label for="name">Nombre:</label>
  <input type="text" id="name" name="name" 
      data-validate="required" data-message="El nombre es obligatorio.">

  <label for="email">Email:</label>
  <input type="email" id="email" name="email" 
      data-validate="email" data-message="El correo no tiene el fomato correcto">

  <label for="phone">Teléfono:</label>
  <input type="number" id="phone" name="phone" 
      data-validate="phone" data-message="El teléfono es requerido y de 9 dígitos">

  <div class="messages"> </div>
  <button type="submit">Enviar</button>
</form>

Luego modificamos el script de validación de formulario, para este caso usamos querySelectorAll para obtener todos los campos que tengan el atributo data-validate y luego usar switch para validar dependiendo del tipo.


document.addEventListener('DOMContentLoaded', function () {

    const $form = document.getElementById('formRegister');

    $form.addEventListener('submit', (e) => {
        e.preventDefault();

        let $fields = $form.querySelectorAll('input[data-validate]');
        let $messages = $form.querySelector('.messages');
        let errors = [];

        $fields.forEach($field => {
            let validate = $field.dataset.validate;
            let value = $field.value.trim();
            let valid = true;

            switch (validate) {
                case 'required':
                    valid = (value.length > 0);
                    break;
                case 'email':
                    valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
                    break;
                case 'phone':
                    valid = /^\d+$/.test(value) && value.length === 9;
                    break;
            }

            if (!valid) {
                $field.classList.add('error');
                errors.push($field.dataset.message);
            } else {
                $field.classList.remove('error');
            }
        });

        // Mostrar mensajes de error
        if (errors.length > 0) {
            $messages.innerHTML = errors.join('
'); $messages.classList.add('show'); } else { $messages.classList.add('remove'); $form.submit(); } }); });

El resultado del ejemplo se puede visualizar en validation-enhanced.html.

Validación Genérica

Ahora creamos una clase genérica FormValidate para validar formularios, esta clase recibe dos parámetros: el formulario que se quiere validar y el elemento donde se pueden mostrar los mensajes de error. Notar que se han implementado 4 tipos de validación:

  • required: para definir que el campo es obligatorio.
  • email: el campo debe tener el formato de correo electrónico.
  • phone: el campo debe ser un número de 9 dígitos.
  • integer: el campo debe ser un número entero.

/**
 * FormValidate
 */
class FormValidate {
    form;
    fields;
    messages;
    errors;

    constructor(form, messages = '') {
        this.form = document.querySelector(form);
        this.messages = document.querySelector(messages);
        this.fields = this.form.querySelectorAll('input[data-validate]');

        this.render();
    }

    render() {
        this.form.addEventListener('submit', (e) => {
            e.preventDefault();
            this.validate();
        });
    }

    validate() {
        this.errors = [];

        this.fields.forEach(field => {
            let validate = field.dataset.validate;
            let value = field.value.trim();
            let valid = true;

            switch (validate) {
                case 'required':
                    valid = (value.length > 0);
                    break;
                case 'email':
                    valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
                    break;
                case 'phone':
                    valid = /^\d+$/.test(value) && value.length === 9;
                    break;
                case 'integer':
                    valid = /^\d+$/.test(value);
                    break;
            }

            if (!valid) {
                this.errors.push(field.dataset.message);
                field.classList.add('error');
            } else {
                field.classList.remove('error');
            }
        });

        // Show error messages
        if (this.errors.length > 0) {
            if (this.messages) {
                this.messages.innerHTML = this.errors.join('
'); this.messages.classList.add('show'); } } else { if (this.messages) { this.messages.classList.add('remove'); } this.form.submit(); } } }

Luego podemos validar el formulario de la siguiente manera:


document.addEventListener('DOMContentLoaded', function () {
    new FormValidate('#formRegister', '#formRegister .messages');
});

El resultado del ejemplo se puede visualizar en validation-generic.html.

Recomendaciones

1. Validación en el Servidor
Aunque la validación en el lado del cliente mejora la experiencia del usuario, siempre valida en el lado del servidor para asegurar que los datos sean correctos y seguros.

2. Filtrado de datos
Filtra los datos para eliminar cualquier código malicioso: puedes eliminar caracteres especiales y secuencias que puedan ser usadas para ataques como XSS.

3. Validar tipo de datos
Asegúrate de que los datos recibidos son del tipo esperado. Por ejemplo, si esperas un número, verifica que el dato sea efectivamente un número.

4. Limitar Longitud de Entradas
Establece límites de longitud razonables para los campos de entrada para evitar ataques como Buffer Overflow.

5. Protección Contra CSRF
Utiliza tokens CSRF para proteger las solicitudes de modificación de datos. Asegúrate de que cada formulario incluya un token CSRF válido.

Librerías de validación

Existen varias librerías que pueden simplificar la validación de formularios en JavaScript, proporcionando una forma más robusta y flexible de manejar la validación. Algunas de las más populares son:

Cada una tiene sus propias ventajas y es adecuada para diferentes casos de uso, por lo que la elección dependerá de las necesidades específicas de tu aplicación.

Conclusión

La validación de formularios con JavaScript es una práctica esencial para mejorar la experiencia del usuario y asegurar la calidad de los datos enviados al servidor.

Referencias

Envíar Comentario

En este sitio los comentarios se publican previa aprobación del equipo de Kodetop. Evita los comentarios ofensivos, obscenos o publicitarios. Si deseas publicar código fuente puedes hacerlo entre las etiquedas <pre></pre>