Larry Lane
Larry Lane

Reputation: 2191

Attaching Event handlers to dynamically created elements with a class using plain JavaScript

I built a function that attaches event handlers to classes. It works fine with elements that already exist in the DOM during page load but fails silently on elements that are added dynamically to the DOM after the page has loaded. I appreciate any suggestions. The code below is part of a JavaScript Library I am devoloping named launchjs https://github.com/bytewarestudios/launchjs. Other solutions that have been suggested point only to JQuery code that I already know how to utilize and I need a JavaScript solution without JQuery.

There is one solution that I believe is close to what I need at Event binding on dynamically created elements? provided by Ram swaroop but I don't believe it points to the root problem I am having with attaching events to dynamically created elements and it doesn't explain it as thoroughly as the accepted answer on this page.

The end result of the code should allow the user to use the following code structure to attach an event to an element with a class.

l(".className").on("click",function(event){

//do something here

});

JavaScript:

/*
  The type parameter passed in to this function is "click" and the 
  selector variable value equals .view
  Note: the isClass function returns true if the selector value is prefixed
 with a .
 */

this.on = function(type,fn){//begin on function


    //store the events
    var events = ["click","mouseover","mouseout","submit","dblclick"];


    //if the event array contains the event and the selector is not a class
    if(events.indexOf(type) !== -1 && !isClass()){//begin if then  


   //add the event listenter to the document
   document.addEventListener(type,function(event){//begin function           

           /*
            if the event listener target id equals the selector id passed to the launch
           function and the selectors doesn't contain the . prefix or class prefix.
             */
    if(event.target.id === selector){//begin if then      




              //call the function passed in as a parameter, pass the event so it can be used.
              fn(event);              


           }//end if then

      });//end function    

    }//end if then


    //if the event array contains the event and the selector is a class
    if(events.indexOf(type) !== -1 && isClass()){//begin if then  





            //store the collection of classes
            var classes = document.getElementsByClassName(selector.split(".")[1]);     

        //loop through the classes and add the event listeners
        for(var i = 0; i < classes.length; i++){

            classes[i].addEventListener(type,function(event){//begin addEventListener function        

           //add functionality for classes
           if(event.target.className === selector.split(".")[1] && isClass()){//begin if then  



              //call the function passed in as a parameter,pass the event so it can be used.
              fn(event);

           }//end if then

            });//end addEventListener function

   }//end for loop

        }//end if then         


    };//end on function  

Upvotes: 1

Views: 904

Answers (1)

halfzebra
halfzebra

Reputation: 6797

You either need to run this code every time you add a new element, while ensuring, that you're not attaching an event listener twice to old elements, or you can use the technique of delegated events, like in .on() from jQuery.

In short, you attach an event listener to a global container, and check clicked element for a specified class. Here is an article on that matter with the concept: DOM Event Delegation without jQuery

There are also a library, written by the same guy for that specific case: https://github.com/ftlabs/ftdomdelegate

Please see my short example of the concept:

var area = document.getElementsByClassName('clickable-area')[0];

area.onclick = function(e) {
  if (e.target.className === 'add-children') {

    var button = document.createElement('button');
    button.className = 'child-button';
    button.innerText = 'Child button';
    area.appendChild(button);

  } else if (e.target.className === 'child-button') {
    e.target.innerText = 'Dynamically added child is clicked';
  }
}
html,
body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}
.clickable-area {
  display: block;
  cursor: pointer;
  background: #eee;
  width: 100%;
  height: 100%;
}
<div class="clickable-area">
  <button class="add-children">Add children</button>
</div>

Upvotes: 4

Related Questions