Event delegation in JavaScript

In the previous lesson, the problem that occurs when adding new elements was described and its solution was given. In this lesson, we will look at a better way to get around the problem - event delegation. Let's analyze it.

As you already know, by clicking on li, we are simultaneously clicking on ul. This is possible due to event bubbling. We can use this to solve our problem: we will hang an event not on each li, but on their parent ul:

list.addEventListener('click', function() { });

Now in the event handler, this will point to the element to which the handler is attached, and event.target will point to the element in which the event happened:

list.addEventListener('click', function(event) { console.log(this); // our list console.log(event.target); // our list item });

Let's make it so that an exclamation mark is added to the end of the li, on which the click happened:

list.addEventListener('click', function(event) { event.target.innerHTML = event.target.innerHTML + '!'; });

Repeat the above solution. Make sure the new li will also respond to the click.

Universal event delegation

The above code is working, however, not without flaws. Let's analyze these disadvantages and write a more universal solution.

The disadvantage of our code will manifest itself when there are some nested tags inside li. In our case, let these be the i tags:

<ul> <li>item <i>italic</i> item</li> <li>item <i>italic</i> item</li> <li>item <i>italic</i> item</li> <li>item <i>italic</i> item</li> <li>item <i>italic</i> item</li> </ul>

In this case, clicking on the i tag will add an exclamation mark to the end of the tag i , and not the li tag, as we would like - after all, exactly the tag in which the event occurred gets into event.target.

You can solve the problem using the method closest:

list.addEventListener('click', function(event) { let li = event.target.closest('li'); if (li) { li.innerHTML = li.innerHTML + '!'; } });

Repeat the above solution.

enru