15

I want to be able to click anywhere inside the body except that one specific element. I can't find out what's wrong with the code I have done.

When I click on the one specific element .except inside body, I don't want it to hide but when I click on body it should hide.

HTML

<html>
  <head>
    <title>Click anywhere except that specific element</title>
  </head>
  <body id="wrapper">
    <center>
      <div id="except"></div>
    </center>
  </body>
</html>

JS

var body = document.getElementById('wrapper');
var except = document.getElementById('except');

if(body.addEventListener)
  body.addEventListener("click", function(){bodyClick("yes")}, false);
else
  body.attachEvent("onclick", bodyClick);

function bodyClick(clicked){

  except.addEventListener("click", exceptClick,false);
  function exceptClick(){
    bodyClick("no");
    if(clicked === "yes")
      except.style.display = "none";
  }

  if(clicked === "yes")
    except.style.display = "none";
  else
    except.style.display = "show";

}

Any help is appreciated. Forgive me for the incorrect formatting (it's my first post here). Thank You!

Prateek Lal
  • 305
  • 1
  • 2
  • 10
  • 1
    You should avoid using keywords like body as variable names. Create a unique, descriptive name for your variables. Also, the center tag is no longer supported by HTML5. Position your elements via CSS. – rby Nov 11 '15 at 18:36

4 Answers4

30

You need to stopPropagation to the outer element.

Here's a simple illustration: http://jsfiddle.net/5mhqrhwk/3/

var body = document.getElementById('wrapper');
var except = document.getElementById('except');

body.addEventListener("click", function () {
    alert("wrapper");
}, false);
except.addEventListener("click", function (ev) {
    alert("except");
    ev.stopPropagation(); //this is important! If removed, you'll get both alerts
}, false);

HTML:

<div id="wrapper">
    <center>
        <div id="except"></div>
    </center>
</div>
Marc
  • 11,403
  • 2
  • 35
  • 45
  • 1
    A whole day of effort figuring what's wrong and why is it calling both the functions and `stopPropagation` did the trick. You are a life saver. – Prateek Lal Nov 11 '15 at 18:52
  • 1
    How does this work? stopPropagation is written after the body.addEventListener. Why doesn't the body event listener trigger if it's written first? – Normajean May 13 '21 at 05:18
  • 1
    i think i get this now. It's because you click on the except div, and then the event propagates up to its parent. so that means the except.addeventlistener will technically execute first, and then the event propagates to the parent, the body div, and execute the body.addeventlistener. So placing the stopPropagation will stop the event 'bubbling up' to the parents. Its very confusing when w3schools states that stop propagation prevents events bubbling up to parents and capturing down to child elements https://www.w3schools.com/jsref/event_stoppropagation.asp – Normajean May 13 '21 at 05:46
3

You don't really need any flags to do this. Just listen on body click and do different thing depending on the item clicked (event.target). This code should do exactly what you wanted (based on your code):

var body = document.getElementById('wrapper');
var except = document.getElementById('except');

if(body.addEventListener)
  body.addEventListener("click", bodyClick, false);
else
  body.attachEvent("onclick", bodyClick);

function bodyClick(event){
  if(event.target != except)
    except.style.display = "none";
}
metal03326
  • 1,213
  • 2
  • 13
  • 15
  • That wont' work if the `except` element has any sub-elements. You will need to `stopPropagation`. For example: `
    except
    subexcept
    ` will still hide the except div if subexcept is clicked.
    – Daniel Moses Nov 11 '15 at 18:32
3

Instead of stopping propagation on the except element, I'd prefer something like this:

var wrapper = document.querySelector('wrapper');  

document.addEventListener('click', function(e) {
   if ( !wrapper.contains(e.target) ) {
       // Do something when user clicked outside of wrapper element
   }
})
Carsten Andersen
  • 162
  • 1
  • 13
0

You are missing one piece to this. You need to stop the event from bubbling up from the except object if it is clicked

except.addEventListener("click", function(event){event.stopPropagation()}, false);
Daniel Moses
  • 5,872
  • 26
  • 39