Domina la Delegación de Eventos en JavaScript: Solución Definitiva para Eventos Duplicados
¿Alguna vez has tenido eventos que se disparan múltiples veces? ¿Tu paginación funciona en la primera página pero no en las siguientes? Te muestro la solución profesional que implementé en mi último proyecto.
❌ El Problema: Eventos que se Duplican
Esto me pasaba con mi sistema de paginación. Cada vez que cambiaba de página, los eventos se acumulaban:
// ❌ ESTO ESTABA MAL - se ejecutaba CADA VEZ que generaba paginación
async lista(page = 1, filtro = '') {
// ... código para obtener datos ...
const html = UI.genePaginacion({/*...*/});
paginacion.innerHTML = html;
// ¡Este event listener se agregaba CADA VEZ!
paginacion.addEventListener('click', (e) => {
if (e.target.tagName === 'A') {
const page = parseInt(e.target.getAttribute('data-page'));
this.lista(page, filtro);
}
});
}
Resultado: Al cambiar a página 2, tenía 2 listeners. Al cambiar a página 3, tenía 3 listeners... ¡un desastre!
✅ La Solución: Delegación de Eventos
La clave está en escuchar una sola vez en un elemento padre estable:
export class Producto extends ModeloBase {
constructor() {
super('productos');
this.inicializarEventos(); // ← UNA SOLA VEZ en el constructor
}
inicializarEventos() {
// 🎯 Escucha en DOCUMENT (siempre presente)
document.addEventListener('click', (e) => {
// Paginación - verifica DINÁMICAMENTE
if (e.target.closest('#paginacion_id') && e.target.tagName === 'A') {
e.preventDefault();
const page = parseInt(e.target.getAttribute('data-page'));
this.lista(page, '');
}
// Filas de tabla - también dinámico
if (e.target.closest('#tabla_producto') && e.target.closest('tr[data-line_id]')) {
const tr = e.target.closest('tr[data-line_id]');
const lineId = tr.getAttribute('data-line_id');
console.log(`ID seleccionado: ${lineId}`);
}
});
}
}
🎯 ¿Por Qué Funciona?
Antes (Problemático)
// Escuchaba en el ELEMENTO (que se regenera)
paginacion.addEventListener('click', callback);
// ↑↑↑ Si el contenido de #paginacion_id cambia, ¡adiós listener!
Ahora (Profesional)
// Escucha en DOCUMENT (siempre existe)
document.addEventListener('click', (e) => {
// Verifica en TIEMPO REAL si el click fue en nuestro elemento
if (e.target.closest('#paginacion_id')) {
// ↑↑↑ Esto funciona aunque #paginacion_id se regenere COMPLETAMENTE
}
});
📈 Beneficios que Obtuve:
| ✅ Una sola asignación | No más eventos duplicados |
| ✅ Funciona con contenido dinámico | Paginación, tabs, modales |
| ✅ Código más limpio | Lógica centralizada |
| ✅ Mejor performance | Menos event listeners en memoria |
🔧 Implementación en tu Proyecto:
class TuClase {
constructor() {
this.inicializarEventos();
}
inicializarEventos() {
document.addEventListener('click', (e) => {
// Tu lógica específica aquí
if (e.target.closest('#tu-elemento-dinamico')) {
// Este código funciona SIEMPRE
}
});
// También aplica para otros eventos
document.addEventListener('submit', (e) => {
if (e.target.closest('#tu-form-dinamico')) {
e.preventDefault();
this.procesarFormulario();
}
});
}
}
💡 Conclusión
La delegación de eventos no es solo una técnica avanzada, es esencial para aplicaciones modernas con contenido dinámico. Desde que implementé este patrón, mis problemas de eventos duplicados desaparecieron.
La delegación de eventos no es solo una técnica avanzada, es esencial para aplicaciones modernas con contenido dinámico. Desde que implementé este patrón, mis problemas de eventos duplicados desaparecieron.
Comentarios
Publicar un comentario