DEV Community

Cover image for Event Delegation in JS
Lu-Vuong Le 🚀
Lu-Vuong Le 🚀

Posted on • Edited on

Event Delegation in JS

What is Event Delegation? ❓

You can look at Event Delegation as a method of handling events for multiple elements via an event listener on one parent element.

Essentially the child elements events will bubble up via Event Bubbling to the parent element and trigger its event listener and then perform some action on the child element via the event.target.

This also allows it to cater for any dynamically generated elements.


Picture this 🖼️

To understand what Event Delegation is, imagine this scenario:

<ul id="brooklyn99Characters">
    <li>Jake Peralta</li>
    <li>Raymand Holt</li>
    <li>Amy Santiago</li>
</ul>

<input id="characterInput" type="text" />
<button id="addBtn" type="button">Add Character</button>
Enter fullscreen mode Exit fullscreen mode
  • You have a list <ul> and list items <li> in the DOM - For each list item, you have an attached event listener listening to a click button that highlights the text when clicked

Some pretty basic concepts so far, you can add an event listener to each of these list items via a loop.

Now imagine that this list has the ability to add new cast characters and essentially is now dynamic.

All of a sudden when a character is added and you try to click on them, nothing happens! 😕

This happens because the event listeners were attached to the elements that were added during page load. When dynamic elements are added to the DOM, the JS is not run and event listeners are not added. This is a common issue you may run into or see others encounter.

Common Event Listener Dynamic Binding Issue


How can we fix this? 🔨

So one common way to fix this problem is to bind these event listeners whenever an element is dynamically generated.

Say you had this code to add a new cast member:

const characterList = document.getElementById('brooklyn99Characters');
const addBtn = document.getElementById('addBtn');
const characterInput = document.getElementById('characterInput');

const highlightText = e => e.target.style.background = 'yellow';

addBtn.addEventListener('click', () => {
    const listItem = document.createElement('li');

    // Set text content to user custom input    
    listItem.textContent = characterInput.value;

    // Bind event listener to this created element
    listItem.addEventListener('click', highlightText);

    characterList.appendChild(listItem);
}
Enter fullscreen mode Exit fullscreen mode

So let's take a look at what is happening:

  • We have a reference to the character list <ul> and a function to style the background of an element to yellow
  • On the add button, we have an event listener which creates an <li> and sets some text (which would be grabbed from an input field)
  • Now we create an event listener for this new dynamically generated element and set in our highlight function. This is the important part which allows the 'rebinding'

  • Finally, we append it to the parent list

Now this is not always the best way to do things, there are some things problematic with this

  1. It can cause you to have a lot of event listeners on your page and can cause performance issues

  2. There can be some memory leaks and issues when it comes to binding and unbinding event listeners


Using Event Delegation 💡

Let's implement Event Delegation to the above code and see what the differences are:

const characterList = document.getElementById('brooklyn99Characters');
const addBtn = document.getElementById('addBtn');
const characterInput = document.getElementById('characterInput');

const highlightText = e => e.target.style.background = 'yellow';

// Listen for events on the parent
characterList.addEventListener('click', e => {
    const targetEl = e.target;

    // Check for node type and execute some code
    if (targetEl && targetEl.nodeName === 'LI') {
        highlightText(e);
    }
});

addBtn.addEventListener('click', () => {
    const listItem = document.createElement('li');

    // Set text content to user custom input    
    listItem.textContent = characterInput.value;

    characterList.appendChild(listItem);
}
Enter fullscreen mode Exit fullscreen mode

As you can see above, we have no longer have any need to assign an event listener in the "addBtn".

  • This is because when the element is added and clicked, Event Bubbling kicks in and bubbles up to the parent and triggers the click event there too.

  • Inside parent element (characterList) we have an event listener for a "click", and inside that, we do some checks for the event target to see if it's a li and then we change the styles!

Both the method above and this Event Delegation have the same result:

Binding Fix


So why use Event Delegation?

So as above, the benefit here is that we only need one event listener and it also caters to dynamically generated elements! 🔥

This can be extremely useful depending on your situation and can save you trouble so it is a good technique to keep in your backpack 😁

Follow and connect with me on:


📹 Youtube: https://www.youtube.com/channel/UCWaB4SBBUCvhYb91fz5Vidg
🐦 Twitter: https://twitter.com/coderarchive
📚 Github: https://github.com/luvuong-le
💼 LinkedIn: https://www.linkedin.com/in/lu-vuongle/
📷 Instagram: https://www.instagram.com/coderarchive/
📝 Dev.to: https://dev.to/coderarchive

Top comments (1)

Collapse
 
studmuffin30 profile image
studmuffin30

Both code using 2 addEventListener,and second code not working ,am i missig something here? sorry im newbie