Using .live('click') inside a .click() function triggers itself

Go To StackoverFlow.com

0

I'm trying to add a $('body').live('click') listener after the user clicks on a div. The purpose is creating a custom dropdown box that the user can open and eventually close by clicking anywhere on the page.

But when I add .live() or .bind() function inside a .click() function, the live() function is triggered for some reason:

$('#myDiv').click(function(){
    $('#myDiv .child').show().addClass('showing');
    $('body').live('click', function(){
           $('#myDiv .child').hide();
           $('body').die();
    })
})

#myDiv is shown but immediately hides, evidenced by the lingering .showing class.

Am I using live() wrong? How do I avoid this recursion?

2012-04-05 02:40
by podcastfan88
explain what are you trying to do rather than explaining what you are currently doing. maybe we can provide an alternative rather than fixing a potentially buggy code - Joseph 2012-04-05 02:47


3

return false will stop event propagation:

    $('#myDiv').click(function(){
    $('#myDiv .child').show().addClass('showing');
    $('body').live('click', function(){
           $('#myDiv .child').hide();
           $('body').die();
    });
    return false;
})
2012-04-05 02:54
by Ilia Frenkel
Thanks, this also worked and it's a bit easier than passing an event and using event.stopPropagation() - podcastfan88 2012-04-05 02:59
Always welcome :- - Ilia Frenkel 2012-04-05 03:03
@stuart - FYI, returning false isn't exactly the same e.stopPropagation(). Returning false causes jQuery to execute both e.stopPropagation() and e.preventDefault(). Maybe doesn't make a different to you in this case, but you should understand that it isn't exactly the same. As far as the event being passed to the event handler, it is always passed to an event handler whether you declare the argument or not - it's always there - jfriend00 2012-04-05 03:03
@jfriend00 I totally agree with you. You should always know what you are doing in your code :- - Ilia Frenkel 2012-04-05 03:08
Also, this example is ready made for .one(). If you use that instead of .live(), then you don't need the .die() line - jfriend00 2012-04-05 03:10
Thanks kindly for the explanation. I'll look into these a bit further - podcastfan88 2012-04-05 03:10


0

Use second body click binding without live (also you don't need it, because it always on page) and use timeout:

$('#myDiv').on('click',function(){
    $('#myDiv .child').show().addClass('showing');
setTimeout(function(){
$('body').on('click', function(){
           $('#myDiv .child').hide();
           $('body').off('click');
    });
},0);

});
2012-04-05 02:44
by Rustam
My tests show this still triggers itself: http://jsfiddle.net/GsP5j/1/. I was using live() because I don't want $('body') to always accept click events - podcastfan88 2012-04-05 02:49
Please re-check variant with timeou - Rustam 2012-04-05 02:53
That worked, thanks for the option - podcastfan88 2012-04-05 03:05


0

Maybe it should work, maybe it shouldn't. But it doesn't. I'd recommend setting up all your event handlers at the beginning, and just have a global variable (e.g.) that tracks whether or not the second event handler should actually respond or not.

2012-04-05 02:50
by dkamins


0

You probably have to stop propagation of the current event to keep it from bubbling up to the body where your new event handler will see it. Further, you can use .one() for a one time event handler:

$('#myDiv').on('click',function(e){
    $('#myDiv .child').show().addClass('showing');
    e.stopPropagation();
    $(document.body).one('click', function() {
           $('#myDiv .child').hide();
    });
})
2012-04-05 02:51
by jfriend00
Thanks, this worked! I've heard about about propagation but never needed to worry about it before - podcastfan88 2012-04-05 02:54
Ads