wjandali
wjandali

Reputation: 112

Noob on JS -- why is document.onclick not working properly?

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

Answers (2)

Ruan Mendes
Ruan Mendes

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.

http://jsfiddle.net/b4PXG/2/

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

freejosh
freejosh

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

Related Questions