Reputation: 31
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!");
}
Upvotes: 3
Views: 3737
Reputation: 32112
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.
Upvotes: 2
Reputation: 630607
First, I'm making an assumption here:
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:
var
declaration on variables (if they aren't already defined elsewhere).data()
to store the id
on the <a>
we just createdThen, 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.
Upvotes: 2
Reputation: 34078
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.
Upvotes: 0
Reputation: 322592
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
.
Upvotes: 1
Reputation: 9247
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.
Upvotes: 0