Making Event Handlers Work for Newly Added Elements - J Query

Problem
You’ve bound one or more event handlers, and they suddenly stop working. It happens after new elements are added dynamically by an Ajax request or simple jQuery operations (append(), wrap(), etc.).

Solution

There are two possible solutions for this recurring problem, each with its own pros and cons:

Rebinding

This approach requires you to call bind() again and again, every time new elements are added.It’s pretty easy to implement and doesn’t require any plugin or new method.You can simply have all the bindings in a function and call it again after each update.

Event delegation

It relies on event bubbling.‡ This is fast and light but requires a little understanding and can be (just) a little tricky at times.
Since jQuery 1.3, there’s built-in support for event delegation. Using it is as simple as using the new live() method instead of bind().

Discussion

Why do event handlers get lost ?

JavaScript, as opposed to CSS, isn’t a declarative language. You don’t describe behaviors, and they get “automagically” applied.
JavaScript, like most other programming languages, is imperative. The developer specifies a sequence of actions to perform, and they get applied as the line of code is reached.
When you add a piece of code like this:

function handler(){ alert('got clicked'); } jQuery('.clickable').bind('click', handler);

this is what you’re “doing”:

  1. Look for all elements with a CSS class “clickable” and save it to the collection.

  2. Bind the “handler” function to the click event of each element in the collection.

If JavaScript/jQuery were interpreted declaratively, the previous code would mean the following:

  1. Each time an element with CSS class clickable is clicked, run the function handler.

However, because JavaScript/jQuery is interpreted imperatively, the only elements that will get bound are those that match the selector at the time it is run. If you add new elements with a clickable class or you remove the class from an element, the behaviors won’t be added or removed for those elements.

A little introduction to event delegation

Event delegation consists of binding once, at the start, and passively listening for events to be triggered. It relies on the fact that many events in the browser bubble up.
As an example, after you click a <div>, its parent node receives the click event as well, and then it passes to the parent’s parent and so on, until it reaches the document element.

Pros and cons of each approach

Rebinding is simple: you just re-add the event handlers. It leads to new problems, such as adding event handlers to elements that were already bound. Some add CSS classes to work around this problem (marking those bound with a certain class).
All this requires CPU cycles every time the elements are updated and requires more and more event handlers to be created.
One way to work around both problems mentioned is to use named functions as event handlers. If you always use the same function, then you’ve solved the duplication problem, and the overhead is smaller.
Still, rebinding can lead to higher and higher amounts of RAM taken as time passes by.

Event delegation just requires an initial binding and there’s no need to deal with rebinding at all. This is quite a relief for the developer and makes the code shorter and clearer. The RAM problem mentioned before doesn’t apply to event delegation.
The content of the page might change, but the active event handlers are always the same.
Event delegation has a catch, though. In order for it to work, the code that handles it (live(), a plugin or your own code) must take the element that got the event
(event.target) and go through its ancestors to see which ones have event handlers totrigger along with some more processing. This means that, while event delegation requiresless binding, it requires more processing each time an event is triggered.
Also, event delegation cannot be used with events that don’t bubble, such as focus and blur. For these events, there’s a workaround that works cross-browser, using the focus in and focus out events in some browsers.

Conclusion

Event delegation seems like a nicer approach, but it requires extra processing.
My advice on this matter is to use live bindings just when you really need them. These are two common situations:

Dynamic elements

You have a list of DOM elements that changes dynamically.

Large lists

Event delegation can work faster when you bind one live binding instead of, say,
100 from the regular ones. This is faster at the start and takes less memory.
If there’s no reason to use live(), then just go for bind(). If you then need to make it live, switching should be just a matter of seconds.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

J Query Topics