Attaching Events To Dynamically Created Elements With Javascript

Whenever you want to respond to an elements event, you can easily add an event listener and do whatever you want when the event occurs.
You have to make sure that either your script tags are below the element you want to create (So the element is loaded in the document before you try to access it) or you can use the JQuery $(document).ready(); function which won’t execute your javascript until the DOM is fully loaded.

However, this isn’t enough for elements that are dynamically generated, because even though you may have waited until the DOM is fully loaded, your element has been added after that, so you need to go about attaching events to your element another way.

There’s an easy way or the hard way, I’ll show you both so you can have a fuller understanding of your options.
Ironically, the hardway looks easy and the easy way looks hard.  The reason I've named them like this is because the "hard" way may make your javascript more difficult to maintain in the future (in my opinion).

The Hard Way:

Immediately after the javascript which creates your element, add some additional javascript to attach the desired event to the element that was just created.

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title></title>
    <script src="Scripts/jquery-1.10.2.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $("#myButton").click(function () {
                $("#myContainer").append("<input id='createdElement' type='button' value='I just got created' />");
                $("#myContainer").append("<input id='anotherCreatedElement' type='button' value='Another created element' />");


                //These will work as the event listeners are being created after the element has been added to the DOM
                $("#createdElement").click(function () {
                    alert("You clicked the createdElement button");
                });

                $("#anotherCreatedElement").click(function () {
                    alert("You clicked the anotherCreatedElement button");
                });
            });
        });
    </script>
    </head>
    <body>
    <input id="myButton" type="button" value="Create Element"/>
    <div id="myContainer">
    <!--The buttons will be dynamically created here when you click myButton-->
    </div>
    </body>
    </html>

In this example, I’ve added a click event handler for each of the buttons that I’ve created.
I’m not a fan of this method, because I think it makes it more difficult the distinguish when an event will fire and you may end up repeating yourself if you want to create another element with the same class in a different part of your code.
I much prefer to have the event handlers on the outer most level, rather than buried within functions and other handlers, I just find it much easier to read.

The Easy Way:

A much easier way of adding event handlers to dynamically created elements is to the event bubbling of the elements container.  This way you can register the event ahead of time, before it’s created (Providing it’s container exists at the time of execution), rather than at the point of creation and ensure you won’t repeat yourself.
It’s a little more complicated to wrap your head around, but I think the benefits outweigh the costs.

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title></title>
    <script src="Scripts/jquery-1.10.2.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $("#myButton").click(function () {
                $("#myContainer").append("<input id='createdElement' type='button' value='I just got created' />");
                $("#myContainer").append("<input id='anotherCreatedElement' type='button' value='Another created element' />");
            });

            //this wont work as it's being called before the button has been rendered
            $("#createdElement").click(function () {
                alert("You clicked the button");
            });

            //this will work
            //myContainer will respond to event bubbling, but ONLY from the id createdElement
            $("#myContainer").on("click", "#createdElement", function () {
                alert("You clicked the button");
            });
        });
    </script>
    </head>
    <body>
    <input id="myButton" type="button" value="Create Element"/>
    <div id="myContainer">
    <!--The buttons will be dynamically created here when you click myButton-->
    </div>
    </body>
    </html>

In the above example I’ve created a single button with the id of myButton, which when clicked will create 2 buttons within the myContainer div.
I’ve wrapped all of the JQuery code in the $(document).ready() function to ensure that when I access the myButton and myContainer elements have already been loaded into the DOM.
The myButton click event that I’m listening for will append the html for 2 buttons to the myContainer div.

In the next bit of javascript is listening for the click event of createdElement, which is dynamically created when you click the myButton element.
However, it will fail.
This is because the event listener is created before createdElement exists in the DOM.

The next part is the clever bit.

Notice that I’ve selecting the myContainer element first and listening to the click event of that and not the button itself.
This is because of how event bubbling works.
The click event for the button within the myContainer element fires and this causes the event to bubble outwards to it’s parent (myContainer), where it’s parent’s click event fires, and so on throughout the document.
However, you’ve got to be careful, because without adding anything else, you’ll be listening to the click even of anything within the container, which may not be desirable.

I’ve used the .on() method of JQuery to listen to the click event of myContainer (which will bubble up from any of it’s children), but also specified the createdElement id.
This means that the event will only respond if the click event originated from an element with an id of createdElement.

Run the code to test this.

If you click on the createdElement button, you will get the alert, but if you click on the anotherCreatedElement button the event will not fire, this is because it it not one of the matched elements that is being listened for.
If you want to make the click event respond, you will need to change "#createdElement", to "#createdElement,#anotherCreatedElement", but only if you want the exact same behaviour.
If you want a different behaviour, you will need to create another event listener, using “#anotherCreatedElement” instead of “#createdElement”

If you enjoyed this article, please consider giving it a +1

Tags: javascript, jquery

Published: 5/12/2014 7:41:19 PM
By: Stephen Warren