Reputation: 572
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?
<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>
*{
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;
}
$('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.
Upvotes: 0
Views: 1567
Reputation: 730
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.
$(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/
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,
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();
}
Upvotes: 1
Reputation: 26360
$(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>
Upvotes: 2
Reputation: 36965
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/
Upvotes: 2
Reputation: 1
This should work, it worked for me (courtesy of dystroy):
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.
Upvotes: 0