0

I have several li elements that get added to a ul list dynamically. In each of the li elements, there's a button. I want to attach a click event to each button, and within the event handler, I want to get properties unique to the li whose button was clicked.

This (non-functional) code illustrates what I want:

$('ul > li > button').each('click', function(){

    var asdf = $('somehow access any arbitrary element in the li whose button was clicked').html();

});

My current solution (below) works, but it forces me to set an id for each li that indicates its position in the list, which for various reasons I'd rather not do.

// In the response function of the AJAX call that populates the list:

$('ul > li').each(function(i){
  $('button', this).click(function(){

    var name = $('ul > li#item'+i+' > .name').html();

  });
});

Is there a better way?

Tyler
  • 2,579
  • 2
  • 22
  • 32
  • Try `$('ul').find('li').forEach(function(item) { $(item).find('button').click(...);})) ` – AlexD Jan 15 '16 at 20:01
  • 1
    Possible duplicate of [Event binding on dynamically created elements?](http://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) – Andreas Jan 15 '16 at 20:02
  • @Andreas: The snag here is that I need access to all elements of the li, of which button is only one. Using the solution offered in that question, wouldn't I just have access to the button's context? – Tyler Jan 15 '16 at 20:12
  • 1
    No -> `$("ul").on("click", "button", function(e) { var btn = $(this), li = button.closest("li"); ... })` – Andreas Jan 15 '16 at 20:15
  • I agree with @Andreas suggestion of using the on() function. – Omar Yafer Jan 15 '16 at 20:32
  • However the right solution has been initially proposed by @DinoMyte. – Nikolay Ermakov Jan 15 '16 at 20:38

4 Answers4

3

You need to delegate the click event by using .on() instead of binding the click event when the elements are dynamically created in the DOM.

 $(document).on("click", 'ul',function(){    
    var name = $(this).find('li#' + num).html();
    alert(name);
  });

Working example : https://jsfiddle.net/DinoMyte/Lkb0s60n/

Event delegation refers to the process of using event propagation (bubbling) to handle events at a higher level in the DOM than the element on which the event originated. It allows us to attach a single event listener for elements that exist now or in the future.

Source : https://learn.jquery.com/events/event-delegation/

DinoMyte
  • 8,737
  • 1
  • 19
  • 26
0

I would recommend something like

$('ul > li > button').click(function(){
    var parent_li = $(this).parents('li'); //You can use class of li.
    var name = parent_li.html(); // Or whatever you want. In this case $(this) is the clicked element
});
GeorgeGeorgitsis
  • 1,262
  • 13
  • 29
  • The problem with this approach is that I would only have access to the button's context, whereas I need access to the whole li. Maybe I could do something with outerHTML, but that seems like a bad idea. – Tyler Jan 15 '16 at 20:09
  • Didn't understand that before. Check my edit. Hope this helps – GeorgeGeorgitsis Jan 15 '16 at 20:11
  • D'oh. parents() was what I needed. Combined this with .on() so I don't need to do it in the ajax response. – Tyler Jan 15 '16 at 20:21
  • This solution won't work if you add any `li`s after appending this `click` event. You need the @DinoMyte solution. – Nikolay Ermakov Jan 15 '16 at 20:22
  • @Ermakov yes of course, but he can set a class in parent
  • and use parents() with that class. It depends on what Tyler needs.
  • – GeorgeGeorgitsis Jan 15 '16 at 20:24
  • I thought he needed what he wrote in the first line: `I have several li elements that get added to a ul list dynamically`. How this solution will work if a new `li` is added? – Nikolay Ermakov Jan 15 '16 at 20:26
  • But the button belongs to the new dynamically added
  • elements, so parents() will find the desired. But as i said before, he can set a specific class to the
  • he wants to capture and use that class in parents().
  • – GeorgeGeorgitsis Jan 15 '16 at 20:30
  • Each `button` is inside a `li`. When he adds a `li` with the `button` inside , a click event will not be binded because binding has happened before and only for the buttons that existed in DOM at that time. The `parents` thing has nothing to do with that - it is just a method to find elements existing in the DOM at the moment of binding. It won't embrace new elements. – Nikolay Ermakov Jan 15 '16 at 20:35