JavaScript + event propagation

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'; 
}

Answers


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/


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>

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.


Need Your Help

Recursive Fibonacci code

java

I have written the Fibonacci series as below.