Event binding on dynamically created elements?
I have a bit of code where I am looping through all the select boxes on a page and binding a .hover
event to them to do a bit of twiddling with their width on mouse on/off
.
This happens on page ready and works just fine.
The problem I have is that any select boxes I add via Ajax or DOM after the initial loop won't have the event bound.
I have found this plugin (jQuery Live Query Plugin), but before I add another 5k to my pages with a plugin, I want to see if anyone knows a way to do this, either with jQuery directly or by another option.
This question's answers are a collaborative effort: if you see something that can be improved, just edit the answer to improve it! No additional answers can be added here
As of jQuery 1.7 you should use jQuery.fn.on
:
Prior to this, the recommended approach was to use live()
:
However, live()
was deprecated in 1.7 in favour of on()
, and completely removed in 1.9. The live()
signature:
... can be replaced with the following on()
signature:
For example, if your page was dynamically creating elements with the class name dosomething
you would bind the event to a parent which already exists (this is the nub of the problem here, you need something that exists to bind to, don't bind to the dynamic content), this can be (and the easiest option) is document
. Though bear in mind document
may not be the most efficient option.
Any parent that exists at the time the event is bound is fine. For example
would apply to
There is a good explanation in the documentation of jQuery.fn.on
.
In short:
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on()
.
Thus in the following example #dataTable tbody tr
must exist before the code is generated.
If new HTML is being injected into the page, it is preferable to use delegated events to attach an event handler, as described next.
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. For example, if the table exists, but the rows are added dynamically using code, the following will handle it:
In addition to their ability to handle events on descendant elements which are not yet created, another advantage of delegated events is their potential for much lower overhead when many elements must be monitored. On a data table with 1,000 rows in its tbody
, the first code example attaches a handler to 1,000 elements.
A delegated-events approach (the second code example) attaches an event handler to only one element, the tbody
, and the event only needs to bubble up one level (from the clicked tr
to tbody
).
Note: Delegated events do not work for SVG.
This is a pure JavaScript solution without any libraries or plugins:
where hasClass
is
Live demo
Credit goes to Dave and Sime Vidas
Using more modern JS, hasClass
can be implemented as:
You can add events to objects when you create them. If you are adding the same events to multiple objects at different times, creating a named function might be the way to go.
You could simply wrap your event binding call up into a function and then invoke it twice: once on document ready and once after your event that adds the new DOM elements. If you do that you'll want to avoid binding the same event twice on the existing elements so you'll need either unbind the existing events or (better) only bind to the DOM elements that are newly created. The code would look something like this:
Try to use .live()
instead of .bind()
; the .live()
will bind .hover
to your checkbox after the Ajax request executes.
You can use the live() method to bind elements (even newly created ones) to events and handlers, like the onclick event.
Here is a sample code I have written, where you can see how the live() method binds chosen elements, even newly created ones, to events:
Single element:
Child Element:
Notice the added *
. An event will be triggered for all children of that element.
I have noticed that:
It is not working any more, but it was working before. I have been using jQuery from Google CDN, but I don't know if they changed it.
Another solution is to add the listener when creating the element. Instead of put the listener in the body, you put the listener in the element in the moment that you create it:
I prefer using the selector and I apply it on the document.
This binds itself on the document and will be applicable to the elements that will be rendered after page load.
For example:
You can attach event to element when dynamically created using jQuery(html, attributes)
.
As of jQuery 1.8, any jQuery instance method (a method of jQuery.fn
) can be used as a property of the object passed to the
second parameter:
Take note of "MAIN" class the element is placed, for example,
In the above scenario, the MAIN object the jQuery will watch is "container".
Then you will basically have elements names under container such as ul
, li
, and select
:
you could use
or
these two methods are equivalent but have a different order of parameters.
see: jQuery Delegate Event
Any parent that exists at the time the event is bound and if your page was dynamically creating elements with the class name button you would bind the event to a parent which already exists
Here is why dynamically created elements do not respond to clicks :
As a workaround, you have to listen to all clicks and check the source element :
This is called "Event Delegation". Good news, it's a builtin feature in jQuery :-)
Try like this -
Use the .on()
method of jQuery http://api.jquery.com/on/ to attach event handlers to live element.
Also as of version 1.9 .live()
method is removed.
More flexible solution to create elements and bind events (source)
Note: This will create an event handler instance for each element (may affect performance when used in loops)
Bind the event to a parent which already exists:
I was looking a solution to get $.bind
and $.unbind
working without problems in dynamically added elements.
As on() makes the trick to attach events, in order to create a fake unbind on those I came to:
I prefer to have event listeners deployed in a modular function fashion rather than scripting a document
level event listener. So, I do like below. Note, you can't oversubscribe an element with the same event listener so don't worry about attaching a listener more than once - only one sticks.
This is done by event delegation. Event will bind on wrapper-class element but will be delegated to selector-class element. This is how it works.
Note: wrapper-class element can be anything ex. document, body or you wrapper. Wrapper should already exists.
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?