0

I'm having trouble with a popup window that, when visible, needs to close when a user clicks on the underlying gray area (the area behind the popup window), and not on the popup window itself.

Is there any way I can achieve this?


HTML

<div>
    <div class="b-popup" id="uploader">
    <div class="b-popup-content" id="uploader">
        Text in Popup<br>
        <a href="javascript:PopUpHide()">Hide popup</a>
    </div>
</div>

CSS

*{
    font-family: Areal;
}
.b-container{
    width:200px;
    height:150px;
    background-color: #ccc;
    margin:0px auto;
    padding:10px;
    font-size:30px;
    color: #fff;
}
.b-popup{
    width:100%;
    min-height:100%;
    background-color: rgba(0,0,0,0.5);
    overflow:hidden;
    position:fixed;
    top:0px;
}
.b-popup .b-popup-content{
    margin:40px auto 0px auto;
    width:600px;
    height: 600px;
    padding:10px;
    background-color: #c5c5c5;
    border-radius:5px;
    box-shadow: 0px 0px 10px #000;
}

JavaScript - jQuery

$('div.b-popup').click(function () {
    PopUpHide();
});

Sample is here: http://jsfiddle.net/p7NbX/15/


I've tried to set function call on div click, but it closes popup if I click on popup content div.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
KorsaR
  • 536
  • 1
  • 10
  • 26
  • In browsers... an html-element is the smallest unit of interaction. So... put any html-element at that place. Bind handler to on-click event of that element. – sarveshseri Feb 03 '15 at 16:17
  • Is "the underlying gray area" the popup mask or the wrapper around the link text? – isherwood Feb 03 '15 at 16:19
  • @isherwood, No, if you click on show popup, popup window will be opened on a dark-grey background – KorsaR Feb 03 '15 at 16:21
  • possible duplicate of [jQuery: Hide popup if click detected elsewhere](http://stackoverflow.com/questions/2329816/jquery-hide-popup-if-click-detected-elsewhere) – isherwood Feb 03 '15 at 16:28

4 Answers4

2

Add a click event listener to the whole .b-popup but close the popup only if the event target is different than the .b-popup-content element (edit: or any of its children, as pointed out by @BrettCaswell), for example:

$('.b-popup').on('click', function(e){
    if( ! $(e.target).is('.b-popup-content, .b-popup-content *') ){
        PopUpHide();
    }

});

http://jsfiddle.net/p7NbX/1515/

pawel
  • 35,827
  • 7
  • 56
  • 53
  • @BrettCaswell you're right, I was only thinking in scope of OP's code, not a more general case. Fixed. – pawel Feb 03 '15 at 19:14
  • pawel, yeah,, it's good to go.. I removed my earlier comment because it sounded kind of abrasive.. sorry about that. – Brett Caswell Feb 03 '15 at 19:32
2

$(document).ready(function(){
    PopUpHide();
    
    $("#popup1").click(function(e){
        if( e.target !== this ) return;
        PopUpHide();
    });
    
});

function PopUpShow()
{
  $("#popup1").show();
  }

function PopUpHide()
{
  $("#popup1").hide();
  }
*{
    font-family: Areal;
}
.b-container{
    width:200px;
    height:150px;
    background-color: #ccc;
    margin:0px auto;
    padding:10px;
    font-size:30px;
    color: #fff;
}
.b-popup{
    width:auto;
    background-color: rgba(0,0,0,0.5);
    overflow:hidden;
    position:fixed;
    top:0px;
    bottom:0px;
    left:0;
    right:0;
}
.b-popup-content{
    margin: 3em auto 0 auto;
    width: 100px;
    height: 40px;
    padding: 0.9em;
    background-color: #c5c5c5;
    border-radius:5px;
    box-shadow: 0.05cm 0.05cm 1em rgba(0,0,0,0.8);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="b-container">
    Sample Text
    <a href="javascript:PopUpShow()">Show popup</a>
</div>
<div class="b-popup" id="popup1">
    <div class="b-popup-content">
        Text in Popup
    <a href="javascript:PopUpHide()">Hide popup</a>
    </div>
</div>
Brett Caswell
  • 732
  • 1
  • 4
  • 16
Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • wouldn't run the snippet properly without adding the other sections.. it takes away from your jQuery implementation a bit, but it at least runs.. – Brett Caswell Feb 03 '15 at 19:38
1

Here's an alternative, that boils down to <Element>.addEventListener(<eventName>, <function>.bind(<this>[,<arg1>][,<arg2>]));

bind wraps the intended function, and performs a call on it using additional specified parameters (args). The first parameter of bind will be the this instance of the function. Setting it to undefined will pass the original this instance.


Short Answer (jQuery)

$(document).ready(function()
{
    $("#popup1").hide();
    $('.b-popup').on('click', function(targetId, e){
        console.log("%o %o %o", targetId, e.target.id, e);
        if( e.target.id !== targetId ){ return; }
        PopUpHide();
    }.bind(undefined, "popup1"));       
});


function PopUpShow(){
    $("#popup1").show();
}
function PopUpHide(){
    $("#popup1").hide();
}

the fiddle: http://jsfiddle.net/p7NbX/1514/


Original Answer

The following sample is really more geared for reuse and oop (ish).

/* I'm going to declare and keep my initialization code in an object. 
   that I'll run when the document is ready. 
*/
var MyHandlerManager = 
{     
    'elms' : [],
    'init': function()
    {            
        var CssSelector = "div.b-popup";
        var elms = document.querySelectorAll(CssSelector);
        for (var i = 0; i < elms.length; i++)
        {                
            elms[i].addEventListener('click', MyHandlers.HidePopupHandler.bind(undefined, elms[i].id));                
        }

        /* you can skip this. 
           You don't need to keep a reference to elms (NodeList) for the EventListeners to function properly.  
        */
        MyHandlerManager.elms = elms;
    }
};

You can do anonymous functions instead of referencing the existing functions as handlers, but I like to declare my handlers this way..

This bring some debugging and runtime considerations; like,

  • clearing out the console.logs lines easier and/or,
  • replacing the handler functions at some later point if need be necessary.

var MyHandlers =
{
    "ShowPopupHandler": function (targetId, e)
    {
        console.log("targetId: %o :: e.target.id: %o :: EventArgs: %o", targetId, e.target.id, e);
        if (e.target.id !== targetId) { return; }

        var elm = document.getElementById(targetId);            
        elm.style.display = "block";
    },
    "HidePopupHandler": function (targetId, e) 
    {
        console.log("targetId: %o :: e.target.id: %o :: EventArgs: %o", targetId, e.target.id, e);
        if (e.target.id !== targetId) { return; }

        var elm = document.getElementById(targetId);            
        elm.style.display = "none";
     }
};

$(document).ready(function(){
    PopUpHide();
    MyHandlerManager.init();
    /* Again, you could just take the code in the init() function
       and run it here..
       using 'bind' to wrap the intended function and call it, passing the elm.id as an argument (first arg) into anonymous functions. 
    */
});

function PopUpShow(){
    $("#popup1").show();
}

function PopUpHide(){
    $("#popup1").hide();
}
Brett Caswell
  • 732
  • 1
  • 4
  • 16
0

This should work, it worked for me (courtesy of dystroy):

Original Answer

If needed, you might want to use the clicked element position and size, using $(this).offset() , $(this).width() and $(this).height(). For example :

$('mydivselector').click(function(e) {
  if (e.pageY > $(this).offset().top + 0.5*$(this).height()) {
      // bottom was clicked

 } else {
      // up of the div was clicked

 }
});

If you want to prevent default action and event propagation, return false from the event handler.

Community
  • 1
  • 1
Zeg
  • 1
  • 1
  • this is interesting, but it addresses a completely different question and concern.. this question is simply about handling **bubbling** events. – Brett Caswell Feb 03 '15 at 19:44