开发者

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


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.


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.


There are a couple issues.

First, that's not how you use .live(). The .live() method is called against a jQuery object that was given a selector. You can do it at any point (even before the DOM loads), and any clicks on the page that match the selector will fire the handler.

In your case, it would go something like:

$('.inbox-link').live('click',function() {
   // whatever
});

In your case, where you're assign a separate handler to each item, you would use .bind instead of live().

As another user mentioned, you'll not have the correct value of i in the handler though. You can use $.each() to overcome this.

$.each(MailInInbox, function( i ) {
    var link = $('<a href="#" class="inbox-link">'+ MailInInbox[i][1] +'</a>');
    link.bind('click', function() {
        LoadMailById(i);
    });
    $('<li></li>').append( link ).appendTo( element );     
});

Now you'll have the correct value of i in the handler for each link.


LoadMailById(i);

i is a reference here and increased on each for-iteration. Thus, after the for loop it holds the value of size; 4.


   link.live('click', (function(index) {
        return function() { 
            LoadMailById(index);
        };
      )(i);
    });

I think this should work to fix the problem. The anonymous function takes your argument i and binds it to the variable index so that when the click even occurs, it's not using the value i leftover from the end of the loop but is instead using it's value at the time of the binding.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜