No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Event delegation

18/28
Recursos

Aportes 28

Preguntas 9

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

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 鈥淚NPUT鈥

Les comparto este art铆culo

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

驴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: 鈥淚MG鈥, 鈥淒IV鈥 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 鈥淓vent 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 鈥渘odeName鈥 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.

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 鈥渞epetidos鈥, 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');
}

鈥淏ig 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');
	}
}

鈥淏ig 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