L70 - Formularios
🧠 Concepto
Section titled “🧠 Concepto”Los formularios son el principal medio de interacción del usuario con una web. JavaScript permite controlar el envío, validar los datos y mejorar la experiencia de usuario sin recargar la página.
💻 Seleccionar un formulario
Section titled “💻 Seleccionar un formulario”// Por IDconst formulario = document.getElementById('form-login');
// Por selector CSSconst form = document.querySelector('form');
// Desde document.forms (HTMLCollection)const primerForm = document.forms[0];const formNamed = document.forms['login']; // <form name="login">
// Acceder a los campos del formularioconsole.log(formulario.elements); // HTMLFormControlsCollectionconsole.log(formulario.elements[0]); // primer campoconsole.log(formulario.elements['email']); // campo con name="email"📝 Evento submit
Section titled “📝 Evento submit”El evento submit se dispara cuando se intenta enviar un formulario (clic en botón submit, Enter en un campo).
formulario.addEventListener('submit', (e) => { e.preventDefault(); // 🚫 Evita la recarga de la página
console.log('Formulario enviado (sin recargar)');
// Procesar los datos...});⚠️ Siempre llamar a
e.preventDefault()si vas a manejar el envío con JS. Si no, el navegador recargará la página (comportamiento por defecto).
💻 FormData: la forma moderna
Section titled “💻 FormData: la forma moderna”FormData es un objeto que captura todos los campos de un formulario de forma automática:
formulario.addEventListener('submit', (e) => { e.preventDefault();
const formData = new FormData(formulario);
// Leer valores individuales console.log(formData.get('email')); // valor del campo name="email" console.log(formData.get('password'));
// Checkboxes y radios console.log(formData.get('suscripcion')); // 'on' si está marcado (sin value)
// Múltiples selecciones (select multiple) console.log(formData.getAll('intereses')); // ['deportes', 'musica']
// Convertir a objeto plano const datos = Object.fromEntries(formData.entries()); console.log(datos);
// Iterar for (const [clave, valor] of formData.entries()) { console.log(clave, valor); }});FormData con archivos
Section titled “FormData con archivos”const inputFile = document.querySelector('input[type="file"]');
formulario.addEventListener('submit', (e) => { e.preventDefault(); const formData = new FormData(formulario);
// Los archivos se manejan automáticamente const archivo = formData.get('avatar'); console.log(archivo.name); // 'foto.jpg' console.log(archivo.size); // 123456 console.log(archivo.type); // 'image/jpeg'
// Enviar con fetch fetch('/api/upload', { method: 'POST', body: formData // No pongas Content-Type, fetch lo pone solo con boundary });});🎯 Validación HTML5
Section titled “🎯 Validación HTML5”El navegador tiene validación nativa sin JavaScript:
<form> <input type="email" required placeholder="Email válido"> <input type="password" minlength="8" required placeholder="Mínimo 8 caracteres"> <input type="text" pattern="[A-Za-z]+" placeholder="Solo letras"> <input type="number" min="18" max="99"> <input type="url"> <button type="submit">Enviar</button></form>Atributos de validación
Section titled “Atributos de validación”| Atributo | Descripción |
|---|---|
required | Campo obligatorio |
minlength / maxlength | Longitud mínima/máxima de texto |
min / max | Valor mínimo/máximo (number, date) |
pattern | Expresión regular que debe cumplir el valor |
type="email" | Valida formato de email |
type="url" | Valida formato de URL |
Deshabilitar validación HTML5
Section titled “Deshabilitar validación HTML5”formulario.setAttribute('novalidate', '');// oformulario.noValidate = true;Útil cuando quieres hacer toda la validación manualmente con JS.
📝 Validación JS personalizada
Section titled “📝 Validación JS personalizada”Constraint Validation API
Section titled “Constraint Validation API”const campo = document.querySelector('#email');
// Verificar validezconsole.log(campo.validity.valid); // true/falseconsole.log(campo.validity.valueMissing); // true si required y vacíoconsole.log(campo.validity.typeMismatch); // true si no es email válidoconsole.log(campo.validity.tooShort); // true si minlength no se cumpleconsole.log(campo.validity.patternMismatch); // true si no cumple pattern
// Mensaje de error personalizadocampo.setCustomValidity('Este campo debe ser un email válido');
// Mensaje predeterminado o personalizadoconsole.log(campo.validationMessage); // 'Este campo debe ser un email válido'Validación manual completa
Section titled “Validación manual completa”formulario.addEventListener('submit', (e) => { e.preventDefault();
let valido = true; const errores = [];
const email = formulario.elements['email']; const password = formulario.elements['password'];
// Limpiar errores previos document.querySelectorAll('.error').forEach(el => el.textContent = '');
// Validar email if (!email.value.trim()) { mostrarError(email, 'El email es obligatorio'); valido = false; } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value)) { mostrarError(email, 'Formato de email inválido'); valido = false; }
// Validar password if (password.value.length < 8) { mostrarError(password, 'La contraseña debe tener al menos 8 caracteres'); valido = false; }
if (valido) { enviarFormulario(new FormData(formulario)); }});
function mostrarError(campo, mensaje) { const error = campo.closest('.campo').querySelector('.error'); if (error) error.textContent = mensaje; campo.classList.add('invalido');}💻 Eventos focus, blur, change, input
Section titled “💻 Eventos focus, blur, change, input”const input = document.querySelector('#nombre');
// focus: el campo recibe el focoinput.addEventListener('focus', () => { console.log('Campo enfocado'); input.style.borderColor = 'blue';});
// blur: el campo pierde el focoinput.addEventListener('blur', () => { console.log('Campo perdió el foco'); input.style.borderColor = ''; // Validar aquí si se quiere validación al salir if (input.value.trim() === '') { mostrarError(input, 'El campo no puede estar vacío'); }});
// change: el valor cambió y perdió el focoinput.addEventListener('change', () => { console.log('Valor final:', input.value);});
// input: se dispara en cada cambio (cada tecla)input.addEventListener('input', () => { console.log('Valor actual:', input.value); // Feedback en tiempo real const contador = document.querySelector('#contador'); if (contador) contador.textContent = input.value.length;});🧠 Ejemplo completo: formulario con feedback
Section titled “🧠 Ejemplo completo: formulario con feedback”formulario.addEventListener('input', (e) => { const campo = e.target; const feedback = campo.parentElement.querySelector('.feedback'); if (!feedback) return;
// Feedback en tiempo real if (campo.validity.valid) { feedback.textContent = '✅ Válido'; feedback.className = 'feedback valido'; } else if (campo.value.length > 0) { feedback.textContent = campo.validationMessage || '❌ Inválido'; feedback.className = 'feedback invalido'; } else { feedback.textContent = ''; }});
formulario.addEventListener('submit', async (e) => { e.preventDefault();
// Validación final if (!formulario.checkValidity()) { formulario.reportValidity(); // Muestra los mensajes nativos return; }
const formData = new FormData(formulario);
try { const response = await fetch('/api/registro', { method: 'POST', body: formData });
if (!response.ok) throw new Error('Error en el servidor');
const resultado = await response.json(); alert('✅ Registro exitoso'); formulario.reset(); } catch (error) { alert(`❌ ${error.message}`); }});🎯 Regla de oro: usa
FormDatapara capturar datos,e.preventDefault()para evitar recargas, validación HTML5 como primera capa y JS para validación avanzada y feedback en tiempo real.