Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JQuery Bind click event to appended element with an argument

I'm trying to populate a ul list with some li elements and give each li element a link that calls the same function with a different argument. However it doesn't seem to work, i've attached the code below, CheckForNewMail is called on document load. Can anyone please help me out?

function CheckForNewMail() {
    //////////////////////////////////////////////////////////////////
    // This will be dynamic
    MailInInbox[0] = new Array("0", "Mail One");
    MailInInbox[1] = new Array("12", "Mail Two");
    MailInInbox[2] = new Array("32", "Mail Three");
    MailInInbox[3] = new Array("5", "Mail Four");
    //////////////////////////////////////////////////////////////////////
    $('#mail-in-inbox').children().remove();

    size = 4; element = $('#mail-in-inbox');
    for(i = 0; i < size; ++i) {
        var link = $('<a href="#" class="inbox-link">'+ MailInInbox[i][1] +'</a>');
        link.live('click', function() {
            LoadMailById(i);
        });
        li = $('<li></li>');
        li.append(link);
        element.append(li);     
    }
}

function LoadMailById(id) {
    alert("Button "+ id +" clicked!");
}
like image 427
Gabor Szauer Avatar asked Nov 28 '25 21:11

Gabor Szauer


2 Answers

First, I'm making an assumption here:

  • That you want the id of the email in that click function, not the index e.g. 0, 12, 32, 5, rather than 0, 1, 2, 3.

Given that (easy to adjust with .index() if the assumption is incorrect), you can do this:

function CheckForNewMail() {
    MailInInbox[0] = ["0", "Mail One"];
    MailInInbox[1] = ["12", "Mail Two"];
    MailInInbox[2] = ["32", "Mail Three"];
    MailInInbox[3] = ["5", "Mail Four"];
    $('#mail-in-inbox').empty();

    var size = 4, element = $('#mail-in-inbox');
    for(i = 0; i < size; ++i) {
      $('<a href="#" class="inbox-link">'+ MailInInbox[i][1] +'</a>')
        .data('id', MailInInbox[i][0]).wrap('<li/>').parent().appendTo(element);
    }
}

There are a few changes here:

  • Array literals, much simpler notation
  • Proper var declaration on variables (if they aren't already defined elsewhere)
  • Using .data() to store the id on the <a> we just created

Then, using that stored data, we can attach a single handler to the #mail-in-inbox container one time (on DOM ready), rather than one to each <a> each time this function runs, it should look like this:

$('#mail-in-inbox').delegate('.inbox-link', 'click', function() {
  alert("Button "+ $.data(this, 'id') +" clicked!");
});

This would display "Button 0 clicked!", "Button 12 clicked", etc. You can test out all of the above in a demo here.

like image 200
Nick Craver Avatar answered Dec 01 '25 09:12

Nick Craver


One problem is that the variable i will always be that of the last link because by the time the user clicks any link, the loop would have completed. One way to fix this would be to use the .data() method to associate a piece of information with each li element:

link.data('mailId', i); // within the loop

Then you can bind a single event handler for all inbox links inside #mail-in-inbox:

$('#mail-in-inbox').on('click', '.inbox-link', function() {
    LoadMailById($(this).data('mailId'));
});

Edited to add: .on() was introduced in jQuery 1.7. If you are using jQuery 1.6 or older, use .delegate() or .live() (as in the question and the original version of this answer) instead.

like image 40
PleaseStand Avatar answered Dec 01 '25 10:12

PleaseStand