How to get the classname index with event delegation in javascript

Let’s say you are using vanilla javascript and you want to create a list of items that will update dynamically.

How do you listen for new items that are added to the DOM. And further, how can you get the index of that item to then call a function?

The answer is javascript event delegation. Event delegation works by listening to a parent div and then using the event fired to get the classname of the item that was clicked.

To learn more, check this video:

But what if you want to also get an id number for the class name? The work around I came up with is to add a second class that is just a number. This can serve as the index…

Here it is in psuedo code

const parentListen=document.getElementById("parent_Div");

foodListListen.addEventListener("click", function(e)
{
console.log(e); //This gives you the full event
console.log(e.target); //This will give you the target clicked
var target=e.target;

//Now you apply logic to find out which child element was clicked.
if (target.matches("span.target")) 
{
    console.log("Target clicked",target.className);

    var className=target.className; //Get the className. Since we are using an index as a className, the className will be something like: "myClass 1"


    var classArray=className.split(" "); //Split the array by space to get the second element. This is not necessary if your only class is the index

    console.log(classArray[1]);
    var idn=classArray[1]; //Get id number from array
    functionCall(idn);//call a function using the index
} 
else 
{
    console.log("Wrong match"); //You can handle cases where the user clicked somewhere other than the desired target
}
}
);

And that is it.
If you are not comfortable using numbers as classes, you could also make them more unique, like classId_1, classId_2… and then parse out the number.

This is my best workaround for getting the class index for a dynamic dom.

Another option though is to listen for a click and then loop through the updated dom, applying listeners to each id. The code for that looks like this:


const parentListen=document.getElementById("parent_Div");
    //The 3 dots turns the node list into an array
    //Cycle through the class names
    [...parentListen].forEach((element,idn) => {
    element.addEventListener("click",function(event) {
    console.log("Index",idn);
    functionCall(idn);
    })
    });

The problem I had with the above code is that you had to trigger this function with another event to get it to refresh the DOM listeners. For this reason, I simply get the class by using the parent event delegation in the first method. I also found this code to have fewer memory leaks than adding a new listener to each element via a loop.

One advantage of having a large parent div listener is that it should use less memory, but if you have a single page app where the user does not often refresh, memory leaks with event listeners are something to be aware of. For my use case, the user will switch pages often enough.

I hope this is helpful.

3 Likes

Another wrinkle in this is when you want to “Bubble” up the parent nodes of an element.

I.E.

<div class="first"><div class="second">Button</div><div>

You can find out that second was clicked using closest. This article explains more: https://gomakethings.com/detecting-click-events-on-svgs-with-vanilla-js-event-delegation/

1 Like

Hmm I am also going to use data attributes to get the data I need to pass to the function instead of coding it in the class name: https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes

2 Likes