Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Binding Events to Not Yet Added DOM Elements with JQuery

4.50/5 (2 votes)
20 Feb 2018CPOL2 min read 22.9K  
Provides tip for attaching events to not yet created DOM element

Introduction

Often it is required, or just case of convenience, to bind event to DOM elements that do not yet exist. Often, such element is generated by third party code and there is no easy way to predict when the elements are actually added to the page. Another typical example - the elements of the same type, with same behavior are generated by user actions, for instance, by adding new item to table, list or tree by button click. There are a lot of other examples. I believe that each developer has experience to combat this issue. There are few common workarounds. I would like to explain one of them that uses JQuery on function.

Code Example

Let's say that there is a page with a tree. Initially, the tree has only root node. Each node has some text and button. On button click, child node is added to the tree.

HTML
<html>
    <header>
        <style>
        a{
            border:1px solid blue;
            display:inline-block;
            margin-right:10px;
            background-color:#CEDDFF;
            color:#004E8E;
            text-decoration:none;
            padding-left:5px;
            padding-right:5px;
        }
        
        li{
            padding-bottom:5px;
        }
        </style>
    </header>
    <body>
        <ul>
            <li>
                <div><a class="add-new-child" href="#" 
                data-child-count="0" title="Add Child">+</a>
                <span>Has children: 0</span></div>
            </li>
        </ul>
        <script src="http://code.jquery.com/jquery-latest.min.js" 
        type="text/javascript"></script>
        <script>
            (function() {

                $(".add-new-child").click(function (event) {
                    var li = $(event.target).closest("li");
                    if (li.find(">ul").length === 0) {
                        li.append("<ul></ul>");
                    }

                    var ul = li.find(">ul");
                    ul.append("<li><div><a class='add-new-child' 
                    href='#' data-child-count='0' title='Add Child'>+
                    </a><span>Has children:0</span></div></li>");

                    var count = parseInt(li.find("> div a").attr("data-child-count")) + 1;
                    li.find("> div a").attr("data-child-count", count);
                    li.find("> div > span").html("Has children: " + count);
                });
            })();
        </script>
    </body>
</html>

The page contains HTML and JavaScript with click event binding that fulfills the desired behaviour. However, after a quick test, it is obvious that there is a bug. The button works only for root node that exists at the moment when the attach event statement is executing. For all nodes that are generated by user click, nothing happens.

Solution

Let's use JQuery on (http://api.jquery.com/on/) function to attach event. According to the documentation, this function can have four parameters:

  • event - the string with event name, click in this case
  • selector - standard JQuery selector to filter events by origin
  • data - data to be passed to the handler
  • handler - handler function

I would like to look at parameter selector closer. What it actually means? If element is bound to event, it reacts not only on action originated at itself, but also on all acts bubbled from children DOM elements. Selector parameter eliminates possible origin of event for children that satisfied it. Look at the DOM tree below:

Consider few examples:

$(A).on("click", function(){alert("On click!")});//click on all elements triggers alert
$(A).on("click", "C", function(){alert("On click!")});//click on C, D, E triggers alert
$(A).on("click", "D", function(){alert("On click!")});//click only on D  triggers alert

It is important to understand that actually such approach binds event to element corresponding to selector in right part - $(A) and this element should exist at the moment attachment statement is executing. At the same time, filtering by origin is happening at the moment of action. In such a way, it is a simulation of binding to element that does not exist yet, the actual event is attached to parent element. The last fact brings some limitation: if bubbling of events is stopped between origin and $(A) element, nothing happens. The element from the right part ($(A)) and left (for example C) should be the closest possible in the DOM tree to avoid the bug mentioned above.

In such a way to fix the example above, the line of code:

JavaScript
$(".add-new-child").click(function (event) {

should be substituted with:

JavaScript
$("body").on("click", ".add-new-child", function (event) {

Conclusion

The JQuery on function provide a way to simulate binding event to DOM elements not yet created. Despite some limitations, this approach seems to be the most straight forward for me.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)