Event in Javascript Part 3
This is in continuation of Event in Javascript Part 2
Event Delegation & Performance tips
Event Delegation is very important in building any large scale application. It’s also useful when you are just building independent component or plugin. Even if you are using any frameworks like Angular, React, Meteor etc… it would be good to know if event delegation support is there or not and how it could be leveraged.
Lets see how to handle it using pure javascript and then you can use the same approach using any framework.
What is Event Delegation
Event Delegation is a process where you are delegating the event handler to some common parent DOM element rather than individual DOM element. For Ex
<div id="randomButtonComponent">
<button>6</button>
<button>7</button>
<button>3</button>
<button>5</button>
<button>2</button>
<button>9</button>
</div>//JSvar buttonElems = document.getElementsByTagName("button");
for (var inc=0,len = buttonElems.length; inc < len; inc++){
buttonElems[inc].addEventListener("click", function(event){
var targetBtn = event.target;
var count = parseInt(targetBtn.innerHTML,10);
count--;
targetBtn.innerHTML = count;
if (count === 0){
targetBtn.setAttribute("disabled","disabled");
targetBtn.removeEventListener("add",arguments.callee);
}
})
}
JS Fiddle Link https://jsfiddle.net/vikash20186/xz5xL44u/
In above example, div contains 6 buttons and on each button click we have to reduce the count by 1 and when it reaches 0 we have to disable the button allowing no more click. We have added click handler on each button. First we get all the buttons present inside the DOM and run a loop for each button. Inside loop, we are
- Creating anonymous function on the fly. (handler function)
- Adding event listener to the button
For 6 elements, we are creating 6 handler function and 6 event bindings. For small number its fine but if div contains 100 or more button, then we are creating so many duplicate copy of the same function and event binding. There are another two problem with this approach
- When we add any button after the initial set up, we need to add event listener to the newly added button. Otherwise it won’t work.
- When we need to remove any button, we need to remove the event binding otherwise it will still remain in the memory even though it’s removed from the DOM as bindings are stored with the browser and it keeps a reference to the DOM element.
We can solve these problems with the help of Event Delegation. Event Delegation is the right way to manage events for the list of items.
Event Delegation
Event delegation means that we can attach only one event listener to the common parent element and not to the individual child. As you know, event bubbles up from the child to the parent and when it reaches parent, we can handle it there by detecting the target property.
For Ex :- We can modify the above example to do the same thing in a better manner using event delegation
<div id="randomButtonComponent">
<button>6</button>
<button>7</button>
<button>3</button>
<button>5</button>
<button>2</button>
<button>9</button>
</div>//JSvar divElem = document.getElementById("randomButtonComponent");
divElem.addEventListener("click", function(event){
var targetBtn = event.target;
// event received from the button
if (targetBtn.nodeName === "BUTTON"){
var count = parseInt(targetBtn.innerHTML,10);
count-- ;
targetBtn.innerHTML = count;
if (count === 0){
targetBtn.setAttribute("disabled","disabled");
}
} else {
console.log("Clicked on something else")
}
});
If you notice, I have removed the event from the buttons and added to the div. Inside the click handler, I am using the target’s node name to check if event is coming from button or not.
We need to distinguish between the events generated by button and which are coming from other than button. I am using nodeName property but we can also check for certain attribute, id, className of the target element. We need to use the “if clause” because the div click handler would be called where ever you click inside the div and not necessarily on buttons. In the case of clicking other than button, we cannot execute the logic for button click. Try to run the code and click on button and on div excluding button.
Advantage of event delegation
- We don’t have to create event listener function and event binding for all the buttons inside the div. He are just creating one event listener for the common parent DIV.
- When we add any button after the initial set up, we don’t have to add any event listener to the newly added button. It will work as is because of the div event listener function.
- When we remove any button from the DOM, we don’t have to remove the event listener as we have not added the event listener to the button. We need to remove the event listener only if we are removing the DIV.
To Summarize Event Delegation
- We should not add event listener to every child element.
- We should add only one event listener to a common parent element.
- Inside parent event listener function, we need to distinguish if event is coming from the target child element or from somewhere else.
- Handle when it comes from the child element.
Some performance tips :-
- Use Event Delegation for list of children.
- Remove any event listener attached to the DOM element before loosing the reference of that element.
- Use event.target or event.currentTarget to get the element rather than querying it again from the DOM tree.
I have created two another example to show the event delegation and why its useful. First without event delegation and second with event delegation.
Below uses event delegation