Marek Brzeziński
Marek Brzeziński

Reputation: 345

JQuery ignores .not() function

I have question, why JQuery ignores .not in this code:

$('body').not('#footer').on('click',function(){
    if (($('#footer')).is(":visible")) {
        $('#footer').fadeOut();
    }
});

Basicly, i want to close #footer, but only by click on other elements than #footer. The code above does his job, but clicking on #footer also fadeOut this element, and this is not desired.

Ond on other side, this will work:

$('div').not('#footer').on('click',function(){
    if (($('#footer')).is(":visible")) {
        $('#footer').fadeOut();
    }
});

Now the downside is, that if i click on div inside #footer, this will also close it, so not perfect solution.

My question is, how i can target all elements to close #footer, but not #footer and his childern.

Thank You for advice.

I have used this selector : $('body').children().not('#footer').on('click',function(){ This above, now closes #footer only when i click on body not #footer itself.

But now, clicking on element lef or right margin does nothing. Screen to be more precisly, in image.enter image description here

Upvotes: 0

Views: 86

Answers (2)

Jamiec
Jamiec

Reputation: 136094

why JQuery ignores .not in this code

Because your body element does not have the id footer but some of your div elements obviously do!


You could do this:

$('div:not(#footer)').on('click',function(){
    // if we're not a child of footer and footer is visible
    if ($(this).parents('#footer').length == 0 && ($('#footer')).is(":visible")) {
        $('#footer').fadeOut();
    }
});

or a better solution is:

$('body').on('click',':not(#footer)',function(){
    // as above
});

As this does not bind an event to every non footer div on the page.

Or you can roll all the work into the delegate's selector to keep it concise.

$('body').on('click',':not(#footer,#footer>*)',function(){
    $("#footer").fadeOut();
});

Just keep in mind that with these delegate solutions, there is significant overhead since for every click on the page the handler will run, not just once, but once for the event.target and each of its .parentNodes.

So in each case, the selector will run and traverse up to the body to see if the element is in #footer.

This means that if you click a node nested 20 elements deep, it'll start on the event.target, traverse up those 20 nodes and see that it's not in the #footer. Then it'll start again on the .parentNode of the event.target and traverse up 19 nodes, then up 18, then 17 and so on.

Furthermore, the .fadeOut() will end up being called multiple times

So you can see that this is pretty inefficient overall.


Also keep in mind that these solutions require that #footer is a direct child of body. If there's some parent element before the body, it'll fade out.

Upvotes: 9

John C
John C

Reputation: 3112

If you want to apply the click function to all elements within body (except #footer) then replace -

$('body').not('#footer').on('click',function(){

With -

$('body').children().not('#footer').on('click',function(){

Upvotes: 1

Related Questions