Reputation: 112
I'm trying to make a gallery of pictures appear when a link is clicked, and disappear when anywhere in the browser window is clicked following that. I can change the function associated with clicking on the "galleryshow" element so that if I click it the gallery is shown and if I click it again the gallery disappears; but if I try to make it so that if the window (or document) is clicked the gallery closes, nothing happens.
This is my code:
function gallerymake() {
document.onclick = function () {gallerytake();};
// document.getElementById("hoverage").onclick = function() {gallerytake();};
document.getElementById("galleryhold").style.visibility="visible";
}
function gallerytake(){
document.getElementById("hoverage").onclick = function () {gallerymake();};
document.getElementById("galleryhold").style.visibility="hidden";
}
Thanks
Upvotes: 2
Views: 5469
Reputation: 92274
freejosh's answer works. However, calling e.stopPropagation()
may have undesired side effects if there are other handlers using event delegation, since those handlers may not get called.
One of the basics of event handling is that they should not affect or depend on other handlers as much as possible, say if you had two buttons needing to show two different divs. By calling e.stopPropagation()
, clicking on one of the popups would not hide the other popup. See document.click keep toggling the menu for an example of where it didn't work since it collided with lightbox event handlers. Therefore, a solution that doesn't affect any other code is to install a document click handler that only does its work if the click didn't come from the button or within your popup.
HTML
Here is my web page <button id="show-btn"> show popup</button>
<div id="modal" > I will show over everything <a href="http://google.com" target="_blank">Google</a></div>
JS
var modal = document.getElementById('modal');
var btn = document.getElementById('show-btn');
btn.onclick = function() {
modal.style.display = "block";
};
document.onclick = function (e) {
e = e || window.event;
var target = e.target || e.srcElement;
if (target !== btn && (!target.contains(modal) || target !== modal)) {
modal.style.display = 'none';
}
}
You can abstract this pattern into a function that creates the doc click handlers
/**
* Creates a handler that only gets called if the click is not within any
* of the given nodes
* @param {Function} handler The function to call (with the event object as
* as its parameter)
* @param {HTMLElement} exclude... If the click happens within any of these
* nodes, the handler won't be called
* @return {function} A function that is suitable to be
* bound to the document click handler
*/
function createDocClickHandler(handler /* [,exclude, exclude, ...] */) {
var outerArgs = arguments;
return function (e) {
e = e || window.event;
var target = e.target || e.srcElement;
// Only call the original handler if the click was outside all the excluded nodes
var isWithinExcluded = false;
for (var i=1; i < outerArgs.length; i++) {
var excluded = outerArgs[i];
if (target === excluded || excluded.contains(target)) {
isWithinExcluded = true;
break;
}
}
if (!isWithinExcluded) {
handler.call(this, e);
}
}
}
var modal = document.getElementById('modal');
var btn = document.getElementById('show-btn');
btn.onclick = function() {
modal.style.display = "block";
};
// Assign the handler that will hide the popup if the clicked
// happened outside of modal and btn
document.onclick = createDocClickHandler(function (e) {
modal.style.display = 'none';
}, modal, btn);
Upvotes: 3
Reputation: 11383
Your click event bubbles up to the document
every time you click the hoverage
element, so gallerymake()
and gallerytake()
are being called. See this page for an explanation of events.
To prevent this use e.stopPropagation()
. See this fiddle for a working example.
Upvotes: 2