DEV Community

Cover image for How to bind events to dynamically created elements in JavaScript
Amer Sikira
Amer Sikira

Posted on • Originally published at webinuse.com

How to bind events to dynamically created elements in JavaScript

This post was originally published at webinuse.com

When working with JavaScript and DOM, we often find ourselves in need of creating some elements dynamically. Especially when working with some tables and fetching data from the server. Sometimes we have to bind events to dynamically created elements. And that is exactly what we are going to do now.

When jQuery was in use (it is still today, but not as much as before) we would do by simply attaching the event to body, and then attaching it to the element. Basically, jQuery would find that element for us in the DOM tree and run the desired function. Let’s see an example.

$("body").on("click", "dynamic-element", function(){});
Enter fullscreen mode Exit fullscreen mode

In the example above, jQuery would attach events to dynamically created elements, or any elements for that matter, that we have passed as a parameter.

Bind events to dynamically created elements through bubbling

The first way we are going to try is to attach events to dynamically created elements using a method of bubbling. What does this mean? This means that we are going to target the parent instead of the actual element. And, then, we are going to check if a user clicked on the element or somewhere else.

<div id="container">
    <button class="click-btn">The First Button</button>
</div>

<script>
    /**
     * First, we select parent element
     * */
    const container = document.querySelector("#container");

    /**
     * After that we add event listener to that element
     * */
    container.addEventListener("click", function(e){
        /**
         * Then, we check if we clicked on an element that has
         * .click-btn class
         * */
        if (e.target.classList.contains('click-btn')) {
            /**
             * If we have clicked on such element we
             * run some function
             * */
          alert(`You have clicked ${e.target.innerHTML}`);
        }
    })

    /**
     * Now let's create our dynamic element
     * Another button
     * */
    const btn = document.createElement("button");
    /**
     * In order for event bubbling to work,
     * we have to add the same class as we used
     * in our eventListener
     * */
    btn.className = "click-btn";
    //Then we add some text inside that button
    btn.innerText = "The dynamically created button";
    //And we append it
    container.appendChild(btn);
</script>
Enter fullscreen mode Exit fullscreen mode

As we can see in the example above, we have added eventListener to the parent, but it will run only if a user clicks on an element with a class click-btn.

After we’ve done that, we dynamically created another button with the same class. And by the logic of things, eventListener will run the same function on that button, as on the one we created in HTML.

How to dynamically attach events to dynamically created elements

The second way to bind events to dynamically created elements is by creating a function and running that function on the elements we’ve created. Sounds confusing? Let’s create some examples.

<div id="container">
    <button class="click-btn">The First Button</button>
</div>

<script>
/**
 * First let's create a function
 * */

function dynamicFunction(e) {
    e.preventDefault();
    alert(`You have clicked on ${e.target.innerHTML}`)
}

/**
 * Now let's create our dynamic element
 * */

//First we select our container
const container = document.querySelector("#container");

//Then, we create a button
const btn = document.createElement("button");
//Then, we add it the same as their respective siblings
btn.className = "click-btn";
//Now, we add it some text
btn.innerText = "The dynamically created button";
//Lastly, append it to the container
container.appendChild(btn);

/**
 * Since we are going to attach eventListener to a class
 * we need a loop
 * */

 //Let's store our elements to variable

 const elements = document.querySelectorAll(".click-btn");

 //Then, we loop through those elements
 for(let i = 0; i < elements.length; i++) {
     //We add eventListener to each element
     elements[i].addEventListener("click", dynamicFunction);
 }
</script>
Enter fullscreen mode Exit fullscreen mode

What we did in this example is instead of setting the event to parent, we set it to the exact elements.

But there is a catch. If we created our button, let’s say after we did .fetch() we would need to run a loop again. Why? Because new elements were not part of the DOM when we run the loop the first time. So we can consider that as a drawback.

Which way is better?

They are equal, depending on our preferences. If we want to write a function once then the first way is better. If we do not mind writing the same code several times, then it does not matter.

If you have any questions or anything you can find me on my Twitter, or you can read some of my other articles like How to simply convert any HTML template into a WordPress theme in under 10 minutes?

Discussion (0)