2

I have an input box that successfully toggles a hidden div. However, I also want the div to hide when the user clicks anything other than the div itself. How might I do this?

html

<input id="inputID" type="text" readonly />
<div id="divID"></div>

js

var divObj = document.getElementById('divID');
var inputObj = document.getElementById('inputID');

inputObj.addEventListener('click', toggleDiv, false);
function toggleDiv(){
    divObj.style.display = (divObj.style.display == 'none') ? 'block' : 'none'; 
}

3 Answers 3

4

Create an event listener on document.body element and check if the event originated from an element inside your div and if not hide it. You can ease this job up a bit by not checking the origin but simply preventing click events from inside your div from bubbling up by calling .stopPropagation() on the event object.

divObj.addEventListener('click', function(e) {
    e.stopPropagation();
}, false);
document.body.addEventListener('click', function(e) {
    divObj.style.display = 'none';
}, false);

Demo: http://jsfiddle.net/ThiefMaster/D7YnS/

Sign up to request clarification or add additional context in comments.

4 Comments

Can you post an example of what that might look like? Sorry, kind of a js noob.
Oh, you have to stop the propagation of the inputObj click event, too. Then it works.
Excellent! I just came to that conclusion as well! Thanks for the help, the js event model just became a bit more clear to me now.
By the way, this won't work in old IE versions (they don't know addEventListener). If you need to support these, consider using jQuery.
0

Let's see if this works

  1. call your normal listener to hide the div
  2. add an additional listener to the body to hide your div if not hidden
  3. add a listener to the div itself to stop the event (2. above)
    • this is known as Event Propagation
    • you click on the div, which eventually is a click on the body
    • you don't want to call 2. when u click inside the div

Also, note that the code above (yours) and below (mine) is not cross-browser (addEventListener doesn't work in IE8 and less) Hoping that you are ignoring this, here goes the HTML with JS

<!DOCTYPE HTML>
<html>
<head>
    <title>Lab</title>
    <style type="text/css">
        #divID {
            width: 100px;
            height: 100px;
            margin: 0 auto;
            margin-top: 85px;
            border: 1px solid #020202;

            // Unnecessary stuff
            -moz-border-radius:     2px;
            -webkit-border-radius:  2px;

            -moz-box-shadow:    0 0 8px #565656;
            -webkit-box-shadow: 0 0 8px #565656;
        }
    </style>
</head>
<body>
    <input id="inputID" type="text" readonly="readonly" />
    <div id="divID"></div>
</body>

<script type="text/javascript">

    var divObj = document.getElementById('divID'),
        inputObj = document.getElementById('inputID');

    inputObj.addEventListener('click', toggleDiv, false);
    document.body.addEventListener('click', docClick, false);
    divObj.addEventListener('click', divClick, false);

    function divClick(e) {
        // if you click any element inside the div
        // when the click reaches the div, stop going above
        e.stopPropagation();
    }

    function docClick(e){
        if (divObj.style.display !== 'none') {
            divObj.style.display = 'none';
        }
    }

    function toggleDiv(e) {
        e.stopPropagation();
        divObj.style.display = (divObj.style.display === 'none') ? 'block' : 'none'; 
    }

</script>

</html>

9 Comments

Yup, by the time he edited his comment, I had written a lot of my answer - so could not help not posting it. By the way, your solution works for only 2 divs, and comes back to ur own question of "What if there were 3 divs". I changed ur JS fiddle to add <div id='div3'> Div 3</div>, and it failed
@JuanMendes, additionally, you are using contains() which brings in jQuery dependability, to cope which, u might have to write ur additional function
I don't know what you tried, but when I add a third div and I call hideWhenClickOutside(div3) it does work jsfiddle.net/qzMnj/3
@JuanMendes you are not getting the point. As per your solution, when you say "but when I add a third div" you have to call hideWhenClickOutside again. Thats the glitch. For 100 divs you would call that 100 times... ?
Not a glitch dude, you only have to call the function once for each div. In your example you have to call three functions and everything is hardcoded , so you'd have to change the body of the function "call function multiple time" is much better than "change the body of the function adding a line that deals with each div" when adding new elements. My answer is generalized, yours is specialized.
|
0

ThiefMaster's approach works but has a small problem to consider if you have multiple places that need to do the same thing. Say you needed to do the same thing with two separate divs, then calling e.stopPropagation() would cause the div1 not to be hidden when clicking div2

Example

div1.addEventListeners('click', function(e){
    e.stopPropagation();
}, false);
div2.addEventListener('click', function(e) {
    e.stopPropagation();
}, false);
document.body.addEventListener('click', function(e) {
    div1.style.display = 'none';
    div2.style.display = 'none';
}, false);

Therefore, a safer alternative is (I'll use jQuery for simplicity) http://jsfiddle.net/qzMnj/1/

$(function() {
    function hideWhenClickOutside(element) {
      $(document).click(function(e){
        if ( !element.contains(e.target)) {
            $(element).hide();
        }
      });
    }

    hideWhenClickOutside(document.getElementById('div1'));    
    hideWhenClickOutside(document.getElementById('div2'));
})

My point is that calling stopPropagation() can have unwanted side-effects, if you don't have to do it, it's better not to, unless you're sure no-one will ever care about that click.

1 Comment

@OmShankar Your comment about my answer should be under my answer, not under your own answer. In any case, I'm not using $.contains from jQuery, I'm using Node.contains. Even if I were, there's a clear disclaimer that I'm using jQuery for simplicity, I'm not going to address browser compatibility issues when the question is not about browser compatibility. Your example uses addEventListener which is not supported in older IE versions, it's the same thing, showing the simplest code to address the problem at hand

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.