Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Event delegation

18/28
Recursos

Aportes 20

Preguntas 5

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta 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.

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.

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)
    
        });
    

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”

Les comparto este artículo

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.

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

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.

(○` 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.

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.

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);

¿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

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.

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