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?

6
  • Try $('ul').find('li').forEach(function(item) { $(item).find('button').click(...);})) Commented Jan 15, 2016 at 20:01
  • 1
    Possible duplicate of Event binding on dynamically created elements? Commented Jan 15, 2016 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? Commented Jan 15, 2016 at 20:12
  • 1
    No -> $("ul").on("click", "button", function(e) { var btn = $(this), li = button.closest("li"); ... }) Commented Jan 15, 2016 at 20:15
  • I agree with @Andreas suggestion of using the on() function. Commented Jan 15, 2016 at 20:32

4 Answers 4

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/

Sign up to request clarification or add additional context in comments.

Comments

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
});

8 Comments

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.
Didn't understand that before. Check my edit. Hope this helps
D'oh. parents() was what I needed. Combined this with .on() so I don't need to do it in the ajax response.
This solution won't work if you add any lis after appending this click event. You need the @DinoMyte solution.
@Ermakov yes of course, but he can set a class in parent <li> and use parents() with that class. It depends on what Tyler needs.
|
0

JSFiddle

JS:

// In the response function of the AJAX call that populates the list:
jQuery('ul > li').each(function(i){
  jQuery('button', this).click(function(){

    var name = $(this).text();
    var className = $(this).attr("class");
// e.g. "1" or "2"    
console.log(name);
// e.g. "one" or "two"    
console.log(className);    
  });
});

HTML:

<ul>
  <li>
    <button class="one">1</button>
  </li>
  <li>
    <button class="two">2</button>
  </li>
  <li>
    <button class="three">3</button>
  </li>
</ul>

Comments

0

The click() function will only bind itself to the items present in the DOM at the moment where the document is loaded. What you need to use is jQUery's on() function.

For on() to work you need an element that exists in the DOM when the script is loaded in this case

<ul class="myList">

With the on() function you add the click event to the selected elements inside the UL.myList. The code

$('.myList').on('click', 'li > button', function(){...});

Would be bindind the click event to all buttons inside an li , that are present inside your UL.myList. These will be binded even if the li>button elements are added after an AJAX call


Example:

(function($) {
  $(document).ready(function() {
    $('#addLi').on('click', function() {
      $(".myList").append($('<li  data-mydata="The new one"><button type="button">btn</button></li>'));
    });

    $('.myList').on('click', 'li > button', function() {
      var thisButton = $(this); //Get the button that was clicked
      var prnt = thisButton.parent(); //Get its parent
      var msg = "I was clicked" + thisButton.prop('tagName') + " My parent is " + prnt.data('mydata'); //Retrieve data of the parent
      alert(msg);
    });
  });
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="myList">
  <li data-mydata="The one">
    <button type="button">btn</button>
  </li>
</ul>

<button type="button" id="addLi">Add LI</button>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.