Adding events to elements on run-time (JavaScript)

I encounter many situations where I have to add events to element in JavaScript runtime, with each element  having similar event handlers with variables, say keys on a numpad, where each key has to register a different digit value. How would you do that?

I used to handle these situations by adding attributes to HTML and accessing the attributes from the event ‘target’ inside the event handler function. There is a problem with that technique.

  1. The event handler has to fetch the attribute and do string processing to flesh out the original parameters.
  2. Manipulation of HTML attributes adds to code latency and code complexity.
  3. String processing to flesh out the parameters adds complexity (e.g regular expression) even to a simplest event handler.

I have two solutions to overcome this particular problem…

Solution 1 (Using JavaScript’s super generous object model)

Anything in JavaScript is an object, extensible object. So you can actually add a property to the DOM object itself in order to access that in event handler run-time.

(function(){
  var wrapper = document.getElementById('wrapper');

  //Generating elements in run-time
  for(var i = 0; i < 12; i += 1){
    var p = document.createElement('p'); //Creating element p
    p.innerHTML = 'Click me! ' + i;
    wrapper.appendChild(p);
    p.i = i;//Attaching a particular variable with value to the DOM object

    p.addEventListener('click', function(e){
      alert('You clicked ' + this.i); //Getting that particular value inside the event handler
    });
  };
}());

You can see a working version here at http://codepen.io/rivalslayer/pen/irteE.

In this example, you can see that I have attached ‘i’ to the object ‘p’ which I can use as a fixed parameter for the event handler. This solution though effective can pose a few problems.

  1. Name conflicts. You can use variable naming conventions and namespaces to counter this problem.
  2. It’s very effective because most of the code is being handled inside the JavaScript engine. Less code latency.
  3. When working with many coders, you might not want to fiddle with the object itself.
  4. The event handler can access all the object properties of the parent by using ‘this’. No need to use “event.target.i”.

Solution 2 (Creating functions with closures)

You can create unique individual functions while defining the event handlers. JavaScript has a very special property called Closure. Once a object has been created, you cannot change the enclosed variables. This also can be used to create dynamic event handlers on run-time.

(function(){
  var wrapper = document.getElementById('wrapper');

  //Generating elements in run-time
  for(var i = 0; i < 12; i += 1){
    var p = document.createElement('p'); //Creating element
    p.innerHTML = 'Click me! ' + i;
    wrapper.appendChild(p); 

    p.addEventListener('click', new function(e){
      var x = i; //Setting the variable inside enclosure
      return function(){ //The actual event handler
        alert('You clicked ' + x);
      };
    });
  };
}());

Try out the code at http://codepen.io/rivalslayer/pen/KBfDm.

In this example, I have returned the event handler function from an object initialization. Here I have used closure. Each time a new object is initialized, it returns a function as the event handler. And thanks to closure, the ‘x’ inside the parent object stay intact. Points to be noted,

  1. Creating functions inside function is discouraged by JSLint, but I believe it’s quite good if used in moderation.
  2. Closure can be a very useful feature if used properly. But one must be careful about naming and scopes when writing complex event handlers.
  3. This method compare to the previous one is a little more memory hogging, but it doesn’t interfere with the original DOM objects.

In both these cases, each time a event handler is initialized a new function or object is created, which is quite a waste. On my next post I will talk about how to efficiently create objects are deal with events dynamically.

You may try fiddling with the codes on CODEPEN.. JavaScript is an amazing creature you can actually enjoy learning about.