No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Event delegation

19/29
Recursos

Aportes 30

Preguntas 10

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

La delegación de eventos es básicamente un contenedor padre que le pasa el evento a todos sus hijos (en realidad no se los está pasando, sino que el contenedor padre sigue estando presente en todos los hijos, es por eso que cuando clicamos a un hijo el evento es disárado).
.
Entendiendo esto, cuando obtenemos el target podemos saber cuál elemento hijo del padre fue clicado, por tanto, con una simple condicional puede ver si el elemento clicado es el que yo quiero.
.
Ojo: Eso no significa que el evento se quite de los demás elementos hijos, si tu clicas cualquier otro elemento hijo el evento se va a disparar sí o sí, pero lo que sucede es que la condición del tarjet no se cumple, por eso no hace nada.
.
Y sabiendo esto, puedes hacer cosas chulas como crear funciones que escuchen eventos dinámicamente, una característica de los eventos es que solo se le aplican a los elementos que están desde el inicio, pero si tu agregas otro nodo desde JavaScript los eventos no se van a escuchar para ese nuevo nodo. Entonces, una técnica que se suele usar es escuchar al padre (o en ocasiones a todo el document) y cada vez que el evento ocurra buscar a todos sus hijos que coincidan con el selector al que queremos aplicarle el evento, de esta forma no importa si los nodos se añaden posteriormente desde JavaScript, el evento será escuchado pues JavaScript directamente irá a buscar todos los nodos hijos que cumplan con dicho selector, por ejemplo:
HTML

<div id="divPadre">
    <div class="div">
        Hola
    </div>
</div>

JavaScript

document.querySelector(".div").addEventListener("click", () => {
    // Hace algo
})

En este caso, si al div padre yo le añadiera desde JavaScript otro elemento con la clase div, el evento NO funcionaría:

const nuevoDiv = document.createElement("div");
nuevoDiv.className = "div";
nuevoDiv.textContent = "Nuevo div"
divPadre.append(nuevoDiv)

Sin emabrgo, al usar la delegación de eventos, puedo escuchar al padre y buscar al hijo que me interesa:

nuevoDiv.addEventListener("click", event => {

    if(event.target.classList.contains("div")) {
        // Código
    }

})

De esta forma, no importa cuantos elementos nuevos agregues al padre desde JavaScript, esto siempre va a funcionar.
.
Ahora, si quieres hacer algo más pro, puedes crear una función en el cual tu le pases un selector en específico para usar dentro del div, así solo tienes que llamar a esa función y pasarle el selector de tal manera que se quede escuchando por cualquier elemento nuevo que sea agregado, algo así:

eventAll("click", parentElement, elementToListen, () => {
    // Has algo
})

Una función de ese tipo sería muy útil, porque así puedo mantener escuchando cada elemento, no importa que se agregue después con JavaScript, y sí, yo ya la cree, de hecho hice una mini librería para escuchar eventos partiendo de esta base, pueden indagar el código aquí:
.
events.js
.
Claro, este código está desactualizado porque tiene un pequeño bug y hay ciertos elementos con los que no funciona, pero para eso podemos usar un MutationObserver que mire cuando el padre haya sido modificado (se le haya agregado un hijo nuevo) y a ese hijo aplicarle el evento, yo ya lo hice pero se los dejo de tarea si tienen cursiodidad sobre eso 👀

📩 Event delegation

<h4>Apuntes</h4>
  • La idea principal es delegar un evento global a un solo nodo y desde esa parte poder delegar todos los eventos que sucedan
  • Se debe usar cuando el número de escuchadores es alto
  • Se trata de identificar de donde proviene el evento, según a ello se lo captura con un condicional y se procede a realizar las operaciones

RESUMEN: La técnica event delegation consiste en dejar todos los eventos sucedan en un elemento superior de tal forma que este los identifique y aplique el procedimiento con condicionales

Event delegation consiste en delegar a un solo padre (el padre) el manejo/escucha de los eventos que nos interesan, de esta manera tendremos un único eventListener en lugar de tener uno por cada elemento lo cual puede impactar en el rendimiento de nuestro sitio web cuando son muchos eventListeners.
Si deseamos manejar la interacción solo sobre un elemento específico dentro del nodo padre, solo se debe especificar dentro de la función, para esto se puede usar la información provista por el elemento event.

Como dato la diferencia entre target y currentTarget radica en que el primero hacer referencia al disparador del evento, donde debemos de interactuar para que este se ejecute. Por otro lado el currentTarget es el nodo padre en el que esta el disparador.

MIS APUNTES EVENT DELEGATION 😎👌


/*Utilizaremos nuestro proyecto anterior para que cuando le de click a cada
  uno de los elemento me salga un alert distinto  */

  
const baseUrl = "https://platzi-avo.vercel.app";
const appNode = document.querySelector('#app');

/* 2 forma le agregaremos el escuchador de eventos al contenedor 
   de  nuestros elementos, a este patron se le conoce como delegacion
   de eventos estamos delegando a un solo nodo que es el padre
   de todos lo queremos escuchar que se encargue de manejar todos 
   los eventos de esa zona.
   
   Es importante este patron cuando manejamos
   una gran cantidad de escuchadores y es manejada por la mayoria
   de frameworks importantates
   
   Esto hara que cuando demos click en cualquier parte del elemento
   se ejecute la alerta esto lo podemos arreglar

   Utilizando un condicional en la que utilizamos el parametro
   de la funcion que devuele el evento y entonces accedemos a la
   propiedad target a nodeName y le decimos que solo cuando el evento
   se hubique en el h2 dispare la alerta
   
   */

   appNode.addEventListener('click', (event) => {
    if(event.target.nodeName === 'H2'){

        window.alert("Hola");

    }
  


   });


 const formatPrice = price => {

    const newPrice = new window.Intl.NumberFormat("es-EN", {
        style: "currency",
        currency: "USD"
    }).format(price) 

    return newPrice;
 }

window
    .fetch(`${baseUrl}/api/avo`)
    .then(respuesta => respuesta.json())
    .then(responseJson =>{

        const todosLosItems = [];
        responseJson.data.forEach(item => {
        
        const imagen = document.createElement('img');
      
        imagen.src = `${baseUrl}${item.image}`;

        imagen.className = "h-16 w-16 md:h-24 md:w-24 rounded-full mx-auto md:mx-0 md:mr-6"
        
    
        const titulo = document.createElement('h2');

        titulo.className = "text-lg";
        
        titulo.textContent = item.name;

        /* 1 forma de hacer que al dar click se ejecute una alerta 
        
            Esto funciona pero hay que tener en cuenta que estamos
            agregando un eventListener por cada elemento que recibimos por
            parte de la API
        
        
        */

        titulo.addEventListener('click', () => {

            window.alert("Hola");
        })


    
        const precio = document.createElement('div');

        precio.className = "text-gray-600";

        precio.textContent = formatPrice(item.price);


         priceAndTitle.className = "text-center md:text-left";
         priceAndTitle.appendChild(titulo);
         priceAndTitle.appendChild(precio);

        const card = document.createElement("div");
        card.className = "md:flex bg-white rounded-lg p-6 hover:bg-gray-300";
        card.append(imagen, priceAndTitle);

        

        const container = document.createElement('div');
        container.appendChild(card);


     
     
            todosLosItems.push(container);
            
        
                
            });
    
            appNode.append(...todosLosItems)
    
        });
    

Yo estuve curioseando y encontré que además de bubling también existe Capturing.

Capturing.

Esta forma de propagación funciona al revés que bubling, va desde el elemento mas afuera, hasta el evento seleccionado, activando así todos los padres que contuviesen el mismo evento.

OJO

No confundir Capturing con está técnica enseñada en clases llamada Event delegation la segunda sigue utilizando la forma de propagación Bubling Solo que le adjunta el Escuchador de eventos al padre, para así reaccionar a todos los clicks dentro de este.

Importante destacar que los elementos dentro target.nodeName son todos en mayusculas.
Si quisieras identificar un div sería "DIV"
un input sería un “INPUT”

El curso esta muy padre! pero neta todo en blanco? XDD mis ojos lloran

Les comparto este artículo

¿Por qué usar event delegation?
Porque cuando agregas un nodo de manera dinámica con JS este no va a poder vincularse con un eventListener. Para ello se usa un padre que se haya cargado desde un inicio.
Este articulo de medium lo explican detalladamente: https://medium.com/@bretdoucette/part-4-what-is-event-delegation-in-javascript-f5c8c0de2983
.
Otra razón es porque afecta el rendimiento, aquí se habla de ello: https://stackoverflow.com/questions/28627606/does-adding-too-many-event-listeners-affect-performance

evento con estilos tailwindcss

const containerCards = document.querySelector('#container');

containerCards.addEventListener('click', (event) => {
    if(event.target.nodeName === 'H2'){
        window.alert('Activaste un evento con el texto');
    }
    if(event.target.nodeName === 'IMG'){
        window.alert('Activaste un evento con la imagen');
    }
});


 const image = document.createElement('img');
        image.src = `${URLmain}${element.image}`;
        image.alt = element.name;
        image.className = 'w-11/12 rounded-full  hover:opacity-75 cursor-pointer';

        const title = document.createElement('h2');
        title.textContent = element.name;
        title.className = 'ml-2 font-medium hover:text-green-500 cursor-pointer';

QUE BUENA clase, estaba construyendo una e-commerce y queria que los productos se habrieran solo al dar click en la imagen.
No olviden que para usar .nodeName es en mayuzcula: “IMG”, “DIV” etc, perdí media hora con eso XD

(○` u′○) ato curioso, las comparaciones del nodeName se hacen siempre en mayusculas.
.

Event delegation

Al patron de la combinación de eventos y su forma del propagarse en el DOM se le llama “Event Delegation” o delegación de eventos.

Ejemplo:

// señalando a todos los P de un div.container
document.querySelector("div.container").addEventListener("click", (event) => {
    console.log(event.target.nodeName)
    if (event.target.nodeName === "P") {
        window.alert("Hola")
    }
})

Nota:
Los “nodeName” se refieren siempre en MAYUSCULAS!

Nota2:
El event delegation es un patron sumamente poderoso que debemos utilizar siempre que sea posible, especialmente cuando el numero de escuchadores de eventos sea relativamente grande o se espera que sea grande.

Esta técnica la utiliza REACT, Angular, Svelte y todos los frameworks, pues cada vez que utilizamos eventos, estos frameworks no agregan directamente a los nos sino que lo agregan al body, al document o cualquier otro elemento que se considera la raíz de la aplicación.

Event delegation

Es una solución eficaz para evitar el stopPropagation. Básicamente lo que debemos es colocar nuestro listener en el elemento padre y en la función a ejecutar colocamos una condicional para saber el tipo de selector que disparo el evento, ya con esta información ejecutamos código según el ejecutor del evento.

Este patrón lo debemos usar siempre que sea posible y mas cuando la cantidad de listener es relativamente enorme.

event.target siempre hará referencia al nodo que recibió el evento. Es muy posible que en este ejemplo este nodo sea un H2, IMG, o la etiqueta que muestra el precio. Para mostar la alerta cada vez que se de un click en la card sin importar que etiqueta interna recibio el click, podemos usar event.target.closest('clase de la card'). Usando la clase de la card, podemos obtener su nodo desde un node hijo.

appNode.addEventListener("click", (evento) => {
    if (evento.target.nodeName === "H2"){ 
        window.alert('Hola');
    } //De esta forma sólo funcionará para los títulos en el nodo H2 en el nodo padre document.
});

De esta forma se encarga de manejar todos los elementos y que escuche solo los que requerimos, esto se usa generalmente cuando los eventos y escuchadores son realmente grandes. Todos los framewoks (Angular, Vue.js, React JS, ect) lo usan por debajo agregándolo al body, document o cualquier que ellos consideren como la raíz.

Un uso magnífico que se me ocurre para el `Event Delegation` es para cuando intento manipular o disparar un evento en un elemento que aún no ha aparecido. No lo había pensado de esta manera, pero si en lugar de esperar al elemento para aplicarle el eventListener, sería genial aplicar esta técnica al padre inmediato que estoy seguro existe, y luego con la condición hacer la comparación. En todas vistas es mucho más eficiente, seguro y estable. Gracias Jonathan, nunca dejo de aprender en Platzi.

good

La delegación de eventos es una técnica en JavaScript que te permite manejar eventos en elementos secundarios mediante la captura y propagación de eventos desde un elemento padre. Esto es útil cuando tienes muchos elementos secundarios y quieres evitar agregar un event listener a cada uno de ellos individualmente.

Les comparto un ejemplo sencillito para quienes lo quieran usar.

Por si quieren conectar en linked in

Tenemos un monton de botones.

<div id="buttons">
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
        <button class="buttonClass">Click me</button>
    </div>

Asi aplicamos el concepto…

document.getElementById("buttons").addEventListener("click", event => {
            if (event.target.className === "buttonClass") {
                console.log("Click! en el boton con target " + event.target.className);
            }
        });


Así quede luego de ver como delego los eventos
esta clase es GOD!

Explicación un poco burda:
Es un Patron, se delega el evento al contenedor padre para no anadir n eventos iguales. Este patrón es útil cuando queremos escuchar el mismo evento en múltiples elementos “repetidos”, también un problema común que resuelve este patrón, es que los eventos solo se encuentran en elementos que están desde el inicio de la renderización de la página, si tu añades un nuevo nodo dinámicamente, este no tendrá el evento que debería.

Antes

<section>
	<div>
		<element>Click me</element>
	</div>
	<div>
		<element>Click me</element>
	</div>
	<div>
		<element>Click me</element>
	</div>
	<div>
		<element>Click me</element>
	</div>
</section>
const element = document.querySellector('element');

element,addEventListener('click', () => {
	alert('I was clicked');
}

“Big O”

Numero de Event Listeners: 4

Numero minimo de Event Listeners: 1

Numero maximo de Event Listeners: n

Despues

<section>
	<div>
		<element>Click me</element>
	</div>
	<div>
		<element>Click me</element>
	</div>
	<div>
		<element>Click me</element>
	</div>
	<div>
		<element>Click me</element>
	</div>
</section>
const section = document.querySellector('section');

section,addEventListener('click', (event) => {
	if (event.target.nodeName === 'element') {
		alert('I was clicked');
	}
}

“Big O”

Numero de Event Listeners: 1

Numero minimo de Event Listeners: 1

Numero maximo de Event Listeners: 1

exelente ejemplificacion de event-delegation

Event delegation

La delegación de eventos es una de las técnicas más utilizadas por librerías como React, y también es una técnica muy utilizada cuando se requiere escuchar eventos en una gran cantidad de elementos hijos, es mucho más eficiente que crear un escuchador de eventos para cada hijo, esto es posible gracias a las fases de captura y de propagación que vimos, la manera de implementarlo es muy similar, sólo que el escuchador de eventos estará en el nodo padre:

// Por ejemplo en una lista de tareas por hacer
// Creamos la función a ejecutar con el click
const handleClick = (e) => {
	// Si el nodo objetivo es un anchor alternamos la clase checked
	// Nota: También podemos filtrar por clases u otras propiedades
	if(e.target && e.target.tagName === "A") {
		e.tarjget.classList.toggle("checked");
	}
}

// Escuchamos el evento click en la lista
const list = document.querySelector(".list").addEventListener("click", handleClick);

La técnica de Delegar Eventos consiste básicamente en **Delegar **a un solo nodo que es el Padre de todo lo que nos interesa escuchar que se encargue de manejar todos los eventos que suceden en esa zona

Funciona igual que la propagacion de eventos de forma inversa, donde si el padre contiene un evento, este se hereda a todos los hijos! si queremos usar de forma condicional a un solo elemento, podemos utilizar de condicion la variable del parametro event.nodeName y asi poder asignarlo una sola vez! y asi no cargar tantos eventos al DOM.

Genial

<h4>Event delegation</h4>

Usar la delegación de eventos nos ayudará mucho para evitar tener que poner eventos por cada elemento. Esto lo debemos usar siempre que podamos cuando tengamos muchos listeners.

const appNode = document.querySelector('#app');

appNode.addEventListener('click', event => {
  if (event.target.nodeName === 'H2') { //Si el elemento es un H2 haz esto, y funciona para todos los H2
    window.alert('hola');
  }
});

Cuando intenté aplicar el Event Delegation me pasaba que cuando clickeaba un elemento dentro de ese ARTICLE, no me disparaba el evento. Entonces lo que hice fue buscar si ese nodo clickeado era hijo del nodo que yo requería. Lo hice de esta manera.

let element = event.target
    for(let x = 0; x < 4; x++){
        if (!(element.nodeName === "ARTICLE")){
            element = element.parentNode            
        } 
        else{
            break;
        }
    }
    

El resultado