Ir al contenido principal

Domina la Delegación de Eventos en JavaScript

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.

Comentarios

Entradas populares de este blog

Instalación y Configuración de MySQL 5.7 en Ubuntu 24.04 LTS

Instalar MySQL 5.7 en Ubuntu 24.04 1. Descargar e instalar MySQL Copiar mkdir ~/mysql57 cd ~/mysql57 wget https://cdn.mysql.com/archives/mysql-5.7/mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz tar -zxvf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz sudo mv mysql-5.7.44-linux-glibc2.12-x86_64 /usr/local/mysql sudo ln -s /usr/local/mysql/bin/mysql /usr/local/bin/mysql 2. Instalar dependencias necesarias IMPORTANTE: Se descargan las versiones nuevas de las librerías y se las vincula con las librerías que necesita MySQL. Copiar sudo apt update # Reemplazo de libaio sudo apt install libaio1t64 # Reemplazo de libtinfo y ncurses sudo apt install libtinfo6 libncurses6 Copiar # Crear los enlaces simbólicos sudo ln -sf /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/libaio.so.1 sudo ln -sf /usr/lib/x86_64-linux-gnu/libtinfo.so.6 /usr/lib/x86_64-linux-gnu/libtinfo.so.5 sudo ln -sf /usr/lib/x86_64-linux-gnu/libncurses.so.6 /usr/lib/x86_64...

Instalar Evolution API en Docker con Redis y PostgreSQL Local

Instalar Evolution API en Docker con Redis y PostgreSQL Local En este tutorial vamos a levantar Evolution API usando Docker , con soporte de Redis para sesiones y PostgreSQL local para almacenar datos de manera persistente y compartida entre varios usuarios. 1. Estructura del proyecto Crea una carpeta para tu proyecto y colócate en ella: mkdir -p ~/docker/evolution-api cd ~/docker/evolution-api 2. Archivo docker-compose.yml Este compose levanta Redis y Evolution API : version: "3.9" services: # ✅ SERVICIO REDIS redis: container_name: evolution_redis image: redis:7-alpine restart: unless-stopped ports: - "6379:6379" volumes: - redis_data:/data command: redis-server --save 60 1 --loglevel warning # ✅ SERVICIO EVOLUTION API evolution-api: container_name: evolution_api image: atendai/evolution-api restart: unless-stopped ports: - "8085:8080" env_file: - .env ...

Instalar Jasper Studio 6.21 para Ubuntu 24.04

Instalar js-studiocomm_6.21.3 en Ubuntu 24.4 Para instalar Jaspersoft Studio en Ubuntu 24.4, sigue estos pasos: 1. Descargar Jasper Studio Descarga la versión js-studiocomm_6.21.3 desde el siguiente enlace: Jaspersoft Studio 6.21.3 2. Crear el directorio de instalación mkdir /opt/jasperstudio 3. Mover el archivo descargado mv /dir_descarga/js-studiocomm_6.21.3_linux_x86_64.tgz /opt/jasperstudio/ cd /opt/jasperstudio 4. Extraer el archivo tar -xvzf js-studiocomm_6.21.3_linux_x86_64.tgz cd js-studiocomm_6.21.3 5. Ejecutar Jaspersoft Studio ./Jaspersoft\ Studio 6. Crear acceso directo en el escritorio Para facilitar el acceso, crea un archivo .desktop en el escritorio: gedit ~/Escritorio/jaspersoft-studio.desktop En el archivo jaspersoft-studio.desktop , agrega lo siguiente: [Desktop Entry] Version=1.0 Ty...