268

I have a tag A in which when clicked on, it appends another tag B to perform an action B on click. So when I click on tag B, action B is performed. However, the .on method does not seems to be working on the dynamically created tag B.

My html and jquery for tag A is as below:

<a id="address" class="add_address btn btn-inverse btn-medium pull-right push-top">Add Shipping address</a>

$('.add_address').click(function(){
    //Add another <a>
    $(document).append('<a id="address"  class="pull-right update btn btn-inverse btn-medium push-top">Update</a>');
})

When tag B is clicked, some action B is performed. My jquery is as below:

$('.update').on('click',function(){
  //action B
});

I have some non dynamic content which has class ".update" as well. In the .on() method above works fine for the non dynamic content, but not for the dynamic content.

How can I make it work for dynamic content?

Paolo Forgia
  • 6,572
  • 8
  • 46
  • 58
kkh
  • 4,799
  • 13
  • 45
  • 73

2 Answers2

600

You have to add the selector parameter, otherwise the event is directly bound instead of delegated, which only works if the element already exists (so it doesn't work for dynamically loaded content).

See http://api.jquery.com/on/#direct-and-delegated-events

Change your code to

$(document.body).on('click', '.update' ,function(){

The jQuery set receives the event then delegates it to elements matching the selector given as argument. This means that contrary to when using live, the jQuery set elements must exist when you execute the code.

As this answers receives a lot of attention, here are two supplementary advises :

1) When it's possible, try to bind the event listener to the most precise element, to avoid useless event handling.

That is, if you're adding an element of class b to an existing element of id a, then don't use

$(document.body).on('click', '#a .b', function(){

but use

$('#a').on('click', '.b', function(){

2) Be careful, when you add an element with an id, to ensure you're not adding it twice. Not only is it "illegal" in HTML to have two elements with the same id but it breaks a lot of things. For example a selector "#c" would retrieve only one element with this id.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 4
    Or `delegate` for pre-1.7 :) – Mathew Thompson Feb 26 '13 at 13:58
  • 1
    Note that delegate and on have parameters reversed: it's on('click', 'selector', function(){...}) but delegate('selector', 'click', function(){...}) – PapaFreud Sep 06 '13 at 11:01
  • This doesn't work well on mobile/tablet devices. – Anna Nov 20 '13 at 16:35
  • @Anna can you provide an example of a case where jQuery works on a tablet and this specific use of `on` doesn't work ? – Denys Séguret Nov 20 '13 at 16:38
  • 1
    I came across this post on stackoverflow which helped me decided I had to use inline call to a Javascript function. http://stackoverflow.com/questions/10165141/jquery-on-and-delegate-doesnt-work-on-ipad – Anna Nov 21 '13 at 17:20
  • 2
    Both the question and answer are awesome.. been racking my brains since yesterday! #smh .. i guess I just earned more programming chops.. – pkanane Feb 28 '14 at 16:35
  • It would be better to narrow down the selector from body to preferably an id if possible for performance, that's one of the reason the live() function got deprecated – Tosh Apr 09 '14 at 21:46
  • @Tosh Please have a look at the question. Especially this part : `$(document).append`. – Denys Séguret Apr 10 '14 at 06:28
  • you are completely right I didn't properly examine the question, but it still might make sense to explain the proper use of .on, since many people refer to stackoverflow for this reason. And also add a comment not to add multiple id's – Tosh Apr 10 '14 at 20:33
  • @Tosh This is reasonable. I edited. – Denys Séguret Apr 11 '14 at 11:51
  • Thanks, it saved a lot of time, I didn't know about that and I was upgrading my code to newer versions of jQuery and was using .live so I thought it could be the same implementation! Cheers. – apz2000 Aug 20 '14 at 17:28
  • `document` alone is preferable to `document.body` as styling can cause `body` to not respond to bubbled *mouse* events. As you suggest, always target the nearest convenient non-changing ancestor to the dynamic element. – iCollect.it Ltd Nov 12 '14 at 11:57
  • hi @DenysSéguret thank you! do i have to put the code in between: $(document).ready(function() { INSERT CODE HERE?? }} for it to work? – BenKoshy Aug 13 '16 at 01:30
30

You are missing the selector in the .on function:

.on(eventType, selector, function)

This selector is very important!

http://api.jquery.com/on/

If new HTML is being injected into the page, select the elements and attach event handlers after the new HTML is placed into the page. Or, use delegated events to attach an event handler

See jQuery 1.9 .live() is not a function for more details.

Community
  • 1
  • 1
Samuel Liew
  • 76,741
  • 107
  • 159
  • 260