.live() not working: How do you bind multiple handlers to a dynamically generated element?
[updated] The 1st jQuery section below dynamically creates an "a.open-popup" element. But after I click on it, I need two handlers to trigger:
1st handler (higher priority): Database write and HTML rewrite
2nd handler: simpleLightbox opens
I have tried the following:
a. adding ".find('a.open-popup')" after the a.open-popup element is dynamica开发者_StackOverflow社区lly created. But this causes the simpleLightbox to open, but the first handler is not triggered.
b. use .live() for the first handler. SimpleLightbox still opens, but not the first handler.
c. with the code below, I am calling .simpleLightbox from within the 1st handler. But neither handler is triggered. In fact, it just tries to go to another page with a URL that ends in "#popup01".
// 2nd handler: SimpleLightbox function is called after it has been defined
$(document).ready(function() {
jQuery('a.open-popup').simpleLightbox({
closeLink:'a.close'
});
});
// "a.open-popup" is dynamically created here
jQuery('.add-inv-button').live('click', function(){
var $InvestmentID = jQuery(this).siblings('input').attr('value');
var $add_points = jQuery(this).siblings('.add-points').html();;
var $inputs = { 'InvestmentID' : $InvestmentID };
var $clicked = this;
var $outputs;
jQuery.ajax({
type: 'POST',
url: '/ajax/add_investment',
dataType: 'json',
data: $inputs,
success: function(data) {
$outputs = data;
if ($outputs.state == 'Plan')
{
// dynamically create the "a.open-popup" element
jQuery($clicked).removeClass('add-inv-button')
.addClass('completed-button member-only')
.html('<img class="left" src="/images/check.png" /> <a class="open-popup did-it member-only" href="#popup01" >I did this investment!</a>');
}
}
});
});
// 1st handler: Database write and HTML rewrite
jQuery('a.open-popup').click(function(){
var $parent = jQuery(this).parent();
var $InvestmentID = $parent.siblings('input').attr('value');
var $inputs;
var $outputs;
$inputs = { 'InvestmentID' : $InvestmentID };
$(this).simpleLightbox({closeLink:'a.close'});
// Database write
jQuery.ajax({
type: 'POST',
url: '/ajax/completed_investment',
dataType: 'json',
data: $inputs,
success: function(data) {
$outputs = data;
// HTML rewrite
if ($outputs.state == 'Begin')
{
$parent.siblings('.plan-msg').remove();
$parent.removeClass('completed-button')
.addClass('add-inv-button ')
.html('+ Add to Your Plan');
$newpoints = '(+' + $outputs.points + " " + $outputs.plural + ")";
$parent.siblings('.done-points').removeClass('done-points')
.addClass('add-points')
.html($newpoints);
}
return false;
}
});
});
It's probably that simpleLightbox already captures your click and it returns false or prevents the default behavior, basically overruling your live click function.
WHat you could do is if simpleLightbox has a callback function, turn that a.popup click function into a method then call it as a simpleLightbox callback OR you could call simpleLightbox after the click function.
Adding a new answer as the first is kinda outdated and is probably wrong(mods please delete or merge if necessary)
Your jQuery('a.open-popup').simpleLightbox call will NOT work because the a.open-popup link is created AFTER the declaration(just like click will not work if the popup was dynamically created). What you need is jquery live(but this only works for click, and other basic jquery events) on the popup click function(plus it seems your other functions are not inside the document.ready function):
// 2nd handler: SimpleLightbox function is called after it has been defined
$(document).ready(function() {
// "a.open-popup" is dynamically created here
jQuery('.add-inv-button').live('click', function(){
var $InvestmentID = jQuery(this).siblings('input').attr('value');
var $add_points = jQuery(this).siblings('.add-points').html();;
var $inputs = { 'InvestmentID' : $InvestmentID };
var $clicked = this;
var $outputs;
jQuery.ajax({
type: 'POST',
url: '/ajax/add_investment',
dataType: 'json',
data: $inputs,
success: function(data) {
$outputs = data;
if ($outputs.state == 'Plan')
{
// dynamically create the "a.open-popup" element
jQuery($clicked).removeClass('add-inv-button')
.addClass('completed-button member-only')
.html('<img class="left" src="/images/check.png" /> <a class="open-popup did-it member-only" href="#popup01" >I did this investment!</a>');
}
}
});
});
// 1st handler: Database write and HTML rewrite
jQuery('a.open-popup').live("click", function(){
var $parent = jQuery(this).parent();
var $InvestmentID = $parent.siblings('input').attr('value');
var $inputs;
var $outputs;
$inputs = { 'InvestmentID' : $InvestmentID };
$(this).simpleLightbox({closeLink:'a.close'});
// Database write
jQuery.ajax({
type: 'POST',
url: '/ajax/completed_investment',
dataType: 'json',
data: $inputs,
success: function(data) {
$outputs = data;
// HTML rewrite
if ($outputs.state == 'Begin')
{
$parent.siblings('.plan-msg').remove();
$parent.removeClass('completed-button')
.addClass('add-inv-button ')
.html('+ Add to Your Plan');
$newpoints = '(+' + $outputs.points + " " + $outputs.plural + ")";
$parent.siblings('.done-points').removeClass('done-points')
.addClass('add-points')
.html($newpoints);
}
return false;
}
});
jQuery(this).simpleLightbox({
closeLink:'a.close'
});
});
});
I would be able to provide a better answer if I knew what simplelightbox plugin that is so if you could provide a link to it's API or plugin page, it would help also.
I'm not sure what simpleLightbox is (perhaps a home-grown plugin?). It's clear that you need to call it before a link is clicked, and it sets up an event for you that handles any future clicks and turns them into lightbox displays instead.
Calling simpleLightbox before your link exists isn't going to help you. Neither is calling it inside your 1st handler, because the link is already clicked. The only place to call simpleLightbox is right after creating the link.
As for your "1st handler" -- live events aren't going to work, unfortunately, because simpleLightbox is going to bind to click. It will get the first shot at the event, and it's going to stop propagation, which means your 1st handler will never run. You need to bind to click as well, BEFORE simpleLightbox does, so you get to go first.
Here's some example code to get you started:
if ($outputs.state == 'Plan')
{
// dynamically create the "a.open-popup" element
jQuery($clicked).removeClass('add-inv-button')
.addClass('completed-button member-only')
.html('<img class="left" src="/images/check.png" /> <a class="open-popup did-it member-only" href="#popup01" >I did this investment!</a>')
.find('a.open-popup')
.click(my1stHandler)
.simpleLightbox({closeLink: 'a.close'});
}
Below this, of course, you should define the function my1stHandler:
// 1st handler: Database write and HTML rewrite
function my1stHandler() {
var $parent = jQuery(this).parent();
.
.
.
return true; // make sure simpleLightbox gets to go after we do
}
Hope this helps!
I had this similar issue. I am having a hard time understanding exactly what you are wanting but I believe you are saying you are wanting to programmatically add another a.open-popup and have the newly created popup have a bound event to the already created event.
One issue I was having that I found worked best was adding all my click events and live events INTO the ready()
function.
Second I would assume you want the a.open-popup click event to be live so that all the newly created a.open-popup links will be bound. I was creating new links programmatically and had to set my click listener to live so that all new a.links would be listening upon creation.
Maybe try something like this.
MODS If I understood this question wrong please delete my answer.
// 2nd handler: SimpleLightbox function is called after it has been defined
$(document).ready(function() {
// "a.open-popup" is dynamically created here
jQuery('.add-inv-button').live('click', function(){
var $InvestmentID = jQuery(this).siblings('input').attr('value');
var $add_points = jQuery(this).siblings('.add-points').html();;
var $inputs = { 'InvestmentID' : $InvestmentID };
var $clicked = this;
var $outputs;
jQuery.ajax({
type: 'POST',
url: '/ajax/add_investment',
dataType: 'json',
data: $inputs,
success: function(data) {
$outputs = data;
if ($outputs.state == 'Plan')
{
// dynamically create the "a.open-popup" element
jQuery($clicked).removeClass('add-inv-button')
.addClass('completed-button member-only')
.html('<img class="left" src="/images/check.png" /> <a class="open-popup did-it member-only" href="#popup01" >I did this investment!</a>');
}
}
});
});
// 1st handler: Database write and HTML rewrite
jQuery('a.open-popup').live('click', function(){
var $parent = jQuery(this).parent();
var $InvestmentID = $parent.siblings('input').attr('value');
var $inputs;
var $outputs;
$inputs = { 'InvestmentID' : $InvestmentID };
$(this).simpleLightbox({closeLink:'a.close'});
// Database write
jQuery.ajax({
type: 'POST',
url: '/ajax/completed_investment',
dataType: 'json',
data: $inputs,
success: function(data) {
$outputs = data;
// HTML rewrite
if ($outputs.state == 'Begin')
{
$parent.siblings('.plan-msg').remove();
$parent.removeClass('completed-button')
.addClass('add-inv-button ')
.html('+ Add to Your Plan');
$newpoints = '(+' + $outputs.points + " " + $outputs.plural + ")";
$parent.siblings('.done-points').removeClass('done-points')
.addClass('add-points')
.html($newpoints);
}
return false;
}
});
});
jQuery('a.open-popup').simpleLightbox({
closeLink:'a.close'
});
});
Also are you wanting the user to have to click the 'Add to plan' link AFTER the a.open-popup link is clicked?
On a side note can you please upload your demo to jsfiddle.net and post the link so we can test to see what exactly is happening?
精彩评论