42

I'm trying to hide a div if the user clicks anywhere BUT the popup OR its children. This is the code I have so far:

$("body").click(function(){
    var $target = $(event.target);
    if(!$target.is(".popup") || !$target.is(".popup").children()){
        $("body").find(".popup").fadeOut().removeClass('active');
    }
});

This works for the .popup div, but if any of its children are clicked, it hides it anyway.

Community
  • 1
  • 1
adamyonk
  • 2,976
  • 4
  • 22
  • 23

12 Answers12

89

You really could simplify this a bit I think:

// If an event gets to the body
$("body").click(function(){
  $(".popup").fadeOut().removeClass("active");
});

// Prevent events from getting pass .popup
$(".popup").click(function(e){
  e.stopPropagation();
});

Clicking on the popup, or any of its children will cause propagation to stop before it reaches the body.

Demo of stopping event-propagation: http://jsbin.com/ofeso3/edit

Sampson
  • 265,109
  • 74
  • 539
  • 565
  • 3
    One minor suggestion is writing $(".popup:visible").fadeOut().removeClass("active"); - I've had problems where the thing reappears just to fade out again. – ehdv Feb 25 '10 at 19:00
  • This seems like a great solution, however, I'm having problems when there are things that need to occur within the popup based on the click event. Specifically, I have a Rails app and am using a :remote => true on a form within the popup window. In this case the AJAX functionality breaks when e.stopPropagation() is used. I had created http://stackoverflow.com/questions/5904602/jquerys-event-stoppropagation-causing-problems-with-rails-remote-true before finding this question. Any way around this? – robertwbradford May 10 '11 at 15:48
  • ... I meant to say "using a :method => :delete, :remote => true on a 'destroy' link_to within the popup window..." – robertwbradford May 10 '11 at 15:56
  • 4
    I think the first line should be $('html'), because otherwise the user can click an area within the browser that's not part of body. This can happen if body doesn't fill the whole browser window. – mlissner Jul 04 '11 at 05:18
  • There are simpler solutions that don't stop event propagation. Stopping event propagation can lead to unintended consequences. More here - https://css-tricks.com/dangers-stopping-event-propagation/ – ctorx Mar 26 '15 at 04:59
  • This didn't work for my case. I find first answer here more general and better: http://stackoverflow.com/questions/28558865/popup-window-close-on-click-outside-not-inside-jquery – besimple Mar 23 '16 at 15:27
  • I have just found a serious issue with tricks like this, so be warned: It will break a lot of form elements. – NoobishPro Jan 18 '17 at 19:06
8

I am using a very simple code for this as :-

$(document).click(function(e){

   if($(e.target).closest('#popupdivID').length != 0) return false;
   $('#popupdivID').hide();
});

this is also useful for dropdown menu. if you have click on dropdown menu and viewing the list and then click on elsewhere in the document then that dropdown should be closed. I have used same code for that also.

Thanks!!

4

Here's a potential solution for certain situations. The popup must have tabindex set for this to work and cannot have any "focusable" elements inside.

$('a').click(function() {
    $('.popup').show().focus();
});
$('.popup').blur(function() {
    $(this).hide();
});

http://jsfiddle.net/d6zw3/

jchavannes
  • 2,440
  • 1
  • 26
  • 15
4

Do this:

$(document).click(function (e) {
    // show_alerts is the class of the link to display the popup
    if (!$(e.target).parents().andSelf().is('.show_alerts')) {
        // hide your popup
    }
});

example: http://jsfiddle.net/Acf3F/

Benjamin Crouzier
  • 40,265
  • 44
  • 171
  • 236
3

Brush up on your boolean logic! :)

if(!$target.is(".popup") && !$target.parents().is(".popup"))
ghoppe
  • 21,452
  • 3
  • 30
  • 21
  • I would have expected `$.fn.is` to be returning boolean values. How does it pull off this magic? – Matchu Feb 24 '10 at 21:50
1

We are using this to show a popup on click and then hide it once you click the same button again or click outside.

function togglePopup(){
  var selector = '#popup',
    $popup = $(selector),
    callback = function(e) {
      if (!$(e.target).parents().andSelf().is(selector)) {
        $popup.hide();
        $(document).off('click', callback);
      }
    };

  $popup.toggle();
  if ($popup.is(':visible')) {
    $(document).on('click', callback);
  }
  return false;
}
grosser
  • 14,707
  • 7
  • 57
  • 61
1
$("body").click(function(event ){
            var $target = $(event.target);
            if(!$target.parents().is(".popup") && !$target.is(".popup")){
                $("body").find(".popup").hide();
            }
        });

this is the solution for me

Tim Head
  • 128
  • 2
  • 5
Stane
  • 11
  • 1
1

As of jQuery 1.7 there is the on() handler, the following works for me, assuming a visible popup contains the class '.activePopup' :

$('body').on('click', ":not(.activePopup)", function(e){
  e.stopPropagation();
  //do your hiding stuff
});
Petter Nordlander
  • 22,053
  • 5
  • 50
  • 84
tapmonkey
  • 141
  • 2
  • 9
1

Here is the code snippet which may help for a html structure

<script>
jQuery(document).click(function() {
        jQuery(".main-div-class .content").css("display","none");
    });

    jQuery(".main-div-class .content").click(function (e) {
        e.stopPropagation();
        //do redirect or any other action on the content
    });     
    jQuery(".main-div-class h4").click(function(e) {
        e.stopPropagation();
        jQuery(this).parent().find(".content").show();
    });
</script>
<div class="main-div-class">
<h4>click here</h4>
<div class='content'>to show content here like this "<a href="http://stackoverflow.com/questions/2329816/jquery-hide-popup-if-click-detected-elsewhere#new-answer">Click</a>" or any other type of content</div>
</div>
Abdul Rehman
  • 689
  • 6
  • 11
1

so updated code may be like this

<script type="text/javascript">
jQuery(document).ready(function(e) {
jQuery(document).click(function() {
        jQuery(".main-div-class .content").css("display","none");
    });

    jQuery(".main-div-class .content").click(function (e) {
        e.stopPropagation();
        //do redirect or any other action on the content
    });     
    jQuery(".main-div-class h4").click(function(e) {
        e.stopPropagation();
        jQuery(this).parent().find(".content").show();
    });
});
</script>
<div class="main-div-class">
<h4>click here</h4>
<div class='content'>to show content here like this "<a href="http://stackoverflow.com/questions/2329816/jquery-hide-popup-if-click-detected-elsewhere#new-answer">Click</a>" or any other type of content</div>
</div>
Abdul Rehman
  • 689
  • 6
  • 11
1

I had issues with all of the solutions here, so after some frustration; I approached the problem from a slightly different direction.

I specifically didn't like attaching click events to the body or document and event.target wasn't reliable enough. I also didn't want to use stopPropagation() as I didn't want to interfere with other events.

Here's how I solved it, hope it helps:

Markup

<div id="ModalBG"></div>
<div id="Modal">Content Here</div>


JavaScript

function showModal(){ $("#Modal, #ModalBG").show(); }

$("#ModalBG").click(function () { $("#Modal, #ModalBG").hide() });


CSS

#Modal{
    z-index: 99;
}


#ModalBG{
    opacity: 0;
    position: fixed;
    top: 0px;
    left: 0px;
    bottom: 0px;
    right: 0px;
    width: 100%;
    height: 100%;
    z-index: 98;
    display: none;
}
Craig Poole
  • 740
  • 8
  • 19
0

I did something like the following. Hope it helps someone

$('body').click(function(e) {
    $('className').click(function(){
         e.stopPropagation();
         $(this).data('clicked', true);
    })
if(!$('.className').data('clicked')){
    // do sth
 } else {
    // do sth else
 }
$('.className').data('clicked', false);