tags:

views:

73

answers:

3

Hey,

I am trying to create a jQuery click function that will close a div when you click on anything besides that div. My problem is that there is a search field and another button inside that div that need to stay open if you click on them.

My current function is:

$("*:not(#header)").click(function() {
    $('#header').slideUp({
        duration: 550, 
        easing: 'easeOutExpo'
    });
});

I want to also say "and is not '#categoryMore' and is not '#headerSearch'" but the syntax I've been using have not been working.

$("*:not(#header, #categoryMore, #headerSearch)")

and

$("*:not(#header), *:not(#categoryMore), *:not(#headerSearch)")

Any ideas? Thanks so much for your help!

+1  A: 

There is a jQuery plugin jQuery outside events you might want to use:

With jQuery outside events you can bind to an event that will be triggered only when a specific “originating” event occurs outside the element in question. For example, you can click outside, double-click outside, mouse-over outside, focus outside (and over ten more default “outside” events). Also, if an outside event hasn’t been provided by default, you can easily define your own.

Sarfraz
+3  A: 

EDIT:

Here's an example you can test. http://jsfiddle.net/yvFcz/

I used slideToggle() for the example so you can more easily test it more than once.


Put a handler on the document that closes #header.

Then place a handler on #header that does event.stopPropagation() to prevent the event from bubbling up to the document when you click inside it.

$(document).click(function() {
    $('#header:visible').slideUp({
        duration: 550, 
        easing: 'easeOutExpo'
    });
});

$('#header').click(function( event ) {
    event.stopPropagation();
});

Note that if any other elements on the page has a click handler that uses event.stopPropagation() or return false;, the event won't bubble up to the document, and your #header won't close.

In that case, you would need to handle it directly in that handler.

patrick dw
that didn't seem to do the trick
j-man86
@j-man86 - Here's an example. (The example uses `slideToggle()` instead.) http://jsfiddle.net/yvFcz/ What didn't work? Are you saying that the `#header` didn't slide? Or that clicking inside the `#header` did make it slide?
patrick dw
sry :)... to specify, clicking inside the #header div still makes it slide.
j-man86
@j-man86 - It shouldn't do that. Make sure you added the `event` parameter to the handler function for `#header` as above. Also make sure you *remove* the code that added a click event to *all* the other elements on the page. `$("*:not(#header)")`
patrick dw
Ok I tried your new code, works great!!!!!
j-man86
@j-man86 - Glad it helped. :o) Don't for get to keep your Accept rate up by "Accepting" this answer if it was helpful. :o)
patrick dw
+1  A: 

I think you can use jQuery not() and it might be as simple as this:

$(document).not('#header, #categoryMore, #headerSearch').click(function() {
    $('#header').slideToggle({
        duration: 550, 
        easing: 'easeOutExpo'
    });
});

This allows you to click anywhere outside of the #header and the action will be triggered. You don't have to worry about other .click() events and their propagation (at least not to my knowledge)... it will just NOT select #header, #categoryMore, and #headerSearch.

You can use jQuery slideToggle() to slide up and down the header and its content whenever you click outside of it. If you only want to hide it, then just use .slideUp() as you do now :)

Hope that helps.

Hristo
Hristo - Using `.not()` in that manner won't actually do anything. The `.not()` method is a means of removing elements from a *set* that match the selector given. Since `$(document)` only returns one element (the `document`), and that element will not match the selector given to `.not()`, nothing will be changed.
patrick dw
@patrick dw... OK I was not aware of that, I'm still pretty new to jQuery. Do you have suggestions on what to replace `$(document)`? We don't have much source code to work with, which is why I went with it in the first place.
Hristo
Hristo - Well, if you were to use `.not()` like that, your selector would need to select *all* elements on the page using `$('*')`. Then `.not()` would filter out those few. **But do not do this.** It is terribly inefficient to add a handler to every element. It is better to place a handler only on the `document`, and let the `click` event naturally bubble up to it and fire the handler.
patrick dw
@patrick dw... Thanks! I hope my solution is not too terrible. I understand now why you chose to answer with the `event.stopPropagation();`. I've used it before, but I just didn't quite understand it.
Hristo
Hristo - Your solution above will trigger the `slideToggle()` even if you click the `#header, #categoryMore, #headerSearch` elements. Having the `.not()` there doesn't change the behavior in this case. It's not bad (like adding a handler to every element), but it doesn't quite work the way OP wanted. Thankfully events do bubble up to the `document` element and the bubbling can be disabled where needed through `stopPropagation()`. :o)
patrick dw
ok COOL! That makes a lot more sense and I see why your solution is better than mine. +1 for taking the time to explain this to me. Thank you!
Hristo