views:

67

answers:

2

The title sums it up.

I simply want to hide #test when anything else than #test or its children is clicked.

Thanks a bunch!

+5  A: 

You can use event bubbling to your advantage here, for example:

$("#test").click(function(e) {
  e.stopPropagation();
});
$(document).click(function() {
  $("#test").hide();
});

If the click came from within #test it stops bubbling up via event.stopPropagation(), if it came from anywhere else the click will (by default) bubble all the way up to document, which has a .click() handler to hide #test.

Nick Craver
Thanks once again dude! :)
Nike
A: 

Maybe something like :

// http://api.jquery.com/delegate/
// http://api.jquery.com/not-selector/

$("body").delegate("*:not(#test)", "click", function () {
    $("#test").hide(); // But would be better to cache $("#test") !
});
MAXymeum Prod.
`return false` prevents the default action, it also calls `.preventDefault()`, they're *not* equivalent. Also it's two handlers *once* not a selector check on **every click** of **every element** in the `document`, the `.stopPropagation()` is *much* cheaper. You don't need the `*` either if you were to do it this way. Also your last 2 methods are *insanely* expensive, they're binding event handlers to **every single element** in the `document` besides `#test` itself, *including* elements inside of `#test`, so they're not even correct.
Nick Craver
I didn't say that ".preventDafault()" and "return false;" are equivalent just that the second is smaller. My last 2 methods are only here for the example, that's why I said the first one is the best (jQuery syntax point of view). Now (performance point of view), I also talked about caching but just mentioned that because it is another story. The universal selector was here only to show him that he can modify it because his question was not very clear (click anywhere but not on #test, really ?). The best answer for this one should be somewhere between ours, does not it ?
MAXymeum Prod.
@MAXymeum - Not really no...my version binds 2 event handlers *once*, and requires no additional work with any other clicks, your first method does a lot of extra work with every click, and your last two are way, *way* more expensive, on any large page they'd lock it up. My point about `return false;` is that they're not interchangeable, you can't just "use the short version" if they're not equivalent, they do different things and you need to be aware of that.
Nick Craver
You are right about ".stopPropagation()" and "return false;", they do different things and we do not need to save a couple of bits in the total file size at this stage so what about ".stopImmediatePropagation()" ? Now forget about my last 2 examples (that we both know are expensives), what kind of extra work ".delegate()" do ? IDs ckecks ?
MAXymeum Prod.
@MAXymeum - Yup, it checks the selector of every click event, and checks if the `event.target` either matches the selector or is contained in something that does, with every click in the `<body>`.
Nick Craver
Yep, and I guess the bubbling to document also works in case of dynamic AJAX-added elements. Thanks for your explanations, I am going to edit my answer to only let the ".delegate()" solution. Can you just add a word about ".stopImmediatePropagation()" please ? Thanks
MAXymeum Prod.
@MAXymeum - Sure :) `.stopImmediatePropagation()` is stopping other events even on the same element level (current element), where as `.stopPropagation()` is for stopping it from going to a parent...and since `document` will always be a parent to `#test`, that's what we're using here. The immediate version is a much rarer use case, usually for `.live()` or `.delegate()` events, or other situations, just uncommon ones.
Nick Craver
Thanks for your time and all the things I have learned today ^^
MAXymeum Prod.