How to bind events in JavaScript to dynamic elements

Written by
Published on

Thanks in part to Ajax and front-end heavy frameworks like React and Angular, much of a website these days is generated in real-time dynamically when the page first loads. And maybe some caching happens afterwards. While binding an event to any DOM elements is a relatively straightforward task:

let div = document.getElementById('div');
div.addEventListener('click', function(e){
   // click code goes here
});

Things get trickier when binding that same event to an element that was just created through JavaScript. And that's because binding events can potentially happen before an element even exists on the page.

There are typically 3 ways that an element can get added to a webpage. The first is simply to have the markup there when the page loads.

<div id='div1'></div>

And binding an event to that element is once again as simple as calling the addEventListener() method with the appropriate arguments.

The next way to add an element to the page is through the use of the document.createElement() method which takes in a single argument, the name of the tag that you wish to create.

let div = document.createElement('div');
div.innerHTML = 'hello world'; document.getElementsByTagName('body')[0].appendChild(div);

Once you call the createElement() method, you can then also call the addEventListener() method on that element, binding whichever event you'd like to it.

And the 3rd way of adding an element to a webpage, is probably the most popular in terms of widespread use so far. And that's to use an HTML template and to insert that template wherever it is that you want to add it on the page. That looks something like the following:

<template id='template1'>
<div id='div1'>Click me</div>
</template>

And the JavaScript would resemble the following:

let element = document.getElementById('tcemplate1').content.cloneNode(true);
document.body.appendChild(element);

You can see the problem with this particular method. Because the template is essentially just a string with no real meaning behind it (until added to the DOM), it's a bit difficult to add an event handler to an element inside of the template.

In this particular example, let's say we wanted to add a click event to the templates only div child. You would need to have a unique ID on the new element and then bind that event listener after the template is loaded.

As you can see, the more dynamic the element is, the harder it is to treat it like any other DOM element on the page.

There is one way however to ensure that your dynamic elements get bound without you having to do any extra work after it is rendered. And that's through the concept of event delegation.

Event delegation

Instead of binding the event handler directly to the element, you will have to bind it to a higher level parent, in this case you can bind it to the document.body.

document.body.addEventListener('click', function(e){
if (e.target.className == 'button'){
   // click logic
}
});

You can then use the given target property to check for your elements proper className or ID  or any other type of query selector that you are using, and perform any logic that you wish done here. The best part is that this will also handle binding events for future elements that will get added to the DOM.

As the name implies, you are essentially delegating the event handler to the parent. This works because of the way that JavaScript handles event binding internally through its event propagation pattern.

Event propagation

Event propagation refers to the way that JavaScript sends up, or propagates, events from a given DOM element, all the way up the document tree to the Window object. For example, take the following scenario as an example:

<div onclick='console.log("1")'>
    <div onclick='console.log("2")'>click</div>
</div>

In this scenario, clicking on the child div element will trigger its own click event, but it will also run back up the DOM tree and trigger any events of the same type within its hierarchy.

alert('1')
alert('2')
click me

Which is why event delegation works. Because we are binding the click event to the parent, any clicks on the children will bubble back up the document tree.

Leave a comment

No messages posted yet
Walter Guevara is a software engineer, startup founder and currently teaches programming for a coding bootcamp. He is currently building things that don't yet exist.

New articles published each week. Sign up for my newsletter and stay up to date.

Add a comment

Send me your weekly newsletter filled with awesome ideas
Post