views:

63

answers:

4

Hi,

I have a menu in jQuery when you click on a link it opens up, but I want it so when you click somewhere else, anywhere else that is not the menu, it becomes hidden.

At the moment I'm binding a click event to

$(':not(#the_menu)')

But this seems like I'm binding a click event to the entire minus the menu, is there a more efficient way of doing something like this?

+7  A: 

The best way to do this is with bubbling capture, like this:

$(document).click(function() {
   //close menu
})

$("#the_menu").click(function(e) {
  e.stopPropagation();
});

How this works is every click bubbles (unless you stop it, usually by return false; or event.stopPopagation()), so whatever you click bubbles all the way up to DOM...if a click does that, we close the menu. If it came from inside the menu, we stop the bubble...so the click doesn't bubble up, triggering a close. This approach uses only 2 event handlers instead of 1 on everything but the menu, so very lightweight :)

Nick Craver
Woops had "Propogation" in there, fixed
Nick Craver
Wow, that's cool. Cheers. Need to check the event bubbling on all the browsers though, you know what there like.Have a bicky.
Smickie
@Smickie - Luckily, jQuery normalizes the bubbling very well (with a *few* exceptions) so `click` works consistently. The big one to watch out for is `change` not bubbling correctly in IE, making `.live("change",..)` problematic.
Nick Craver
A: 

Attach event to document's body ($(body)). Also attach another event to #the_menu that's block event propagation:

$(document.body).click(function() {
     //close menu if opened
});

$("#the_menu").click(function(e) {
     //code heere

     e.stopPropagation();
});
Crozin
A: 

anything else than using

$(':someselector')

is more efficient in this case. That is the exact equivalent to

$('*:someselector')

and that is the universal selector that is beyond slow. So, I'd either specify the selector to

  $('div:not(#the_menu)')

or even more specific. Another thing you could do is bind a click event to the document.body and check for the event.target.

Kind Regards

--Andy

jAndy
A: 

How about binding the menu display to hovering over the element in which it is contained?

$("#parentId").hover(
    function() { //!! on hovering in
        $("#targetId").attr("display","block") ;
    } ,
    function() { //!! on hovering out
        $("#targetId").attr("display","none") ;
    }
) ;

If it fits your goal, this seems easier to maintain.

FK82