JTrixx16 JTrixx16 - 1 year ago 45
Javascript Question

Sub-menu does not hide when it is not the click target

I've been struggling for days fixing this simple problem. The sub-menu of one of my navigation menu's tabs is supposed to be closing when other elements are being clicked but it won't close.



var query = document.querySelector.bind(document);

query('.drop-down').onclick = function() {
query('.sub-menu').classList.toggle('nav-show');
}

window.onclick = function(e) {
if (query('.sub-menu').style.display == 'block') {
if (e.target != query('.sub-menu')) {
query('.sub-menu').classList.remove('nav-show');
}
}
}

.menu {
display: table;
background: #f9f8f8;
padding: 0;
margin: 5em auto;
border-radius: 0.5em;
box-shadow: 0 3px 8px -5px rgba(0, 0, 0, 0.8);
}
.menu > li {
display: table-cell;
width: 100px;
list-style: none;
text-align: center;
}
.menu > li.drop-down {
position: relative;
}
.menu > li > a {
display: block;
text-decoration: none;
color: #9c9c9f;
padding: .8em;
font: 1em Arial, sans-serif;
}
.menu > li > a:hover {
color: #757579;
}
.sub-menu {
position: absolute;
padding: 0;
top: 100%;
right: 0;
left: 0;
background: #f9f8f8;
border: 1px solid #f1f1f1;
box-shadow: 0 3px 8px -5px rgba(0, 0, 0, 0.8);
display: none;
}
.sub-menu.nav-show {
display: block;
}
.sub-menu > li {
list-style: none;
display: block;
text-align: center;
}
.sub-menu > li:not(:first-child) {
border-top: 1px solid #f1f1f1;
}
.sub-menu > li > a {
text-decoration: none;
display: block;
font: 0.9em Arial, sans-serif;
color: #9c9c9f;
padding: 1em 0;
}
.sub-menu > li > a:hover {
background: white;
}

<ul class="menu">
<li><a href="" onclick="return false">Home</a>
</li>
<li class="drop-down"><a href="" onclick="return false">Projects</a>
<ul class="sub-menu">
<li><a href="/">HTML</a>
</li>
<li><a href="/">CSS3</a>
</li>
<li><a href="/">JavaScript</a>
</li>
<li><a href="/">PHP</a>
</li>
</ul>
</li>
<li><a href="" onclick="return false">Forums</a>
</li>
<li><a href="" onclick="return false">Blog</a>
</li>
</ul>





Can someone help me fix this problem?

Answer Source

You will need the stopPropagation() method to prevent any parent event handlers from being executed. See w3 wiki for more information.

Here's a quick example with jQuery:

$(".drop-down").click(function(e) {
  e.stopPropagation();
  $('.sub-menu').toggleClass('nav-show');
});

$(document).click(function(e) {
    $('.sub-menu').removeClass('nav-show');
});
.menu {
  display: table;
  background: #f9f8f8;
  padding: 0;
  margin: 5em auto;
  border-radius: 0.5em;
  box-shadow: 0 3px 8px -5px rgba(0, 0, 0, 0.8);
}
.menu > li {
  display: table-cell;
  width: 100px;
  list-style: none;
  text-align: center;
}
.menu > li.drop-down {
  position: relative;
}
.menu > li > a {
  display: block;
  text-decoration: none;
  color: #9c9c9f;
  padding: .8em;
  font: 1em Arial, sans-serif;
}
.menu > li > a:hover {
  color: #757579;
}
.sub-menu {
  position: absolute;
  padding: 0;
  top: 100%;
  right: 0;
  left: 0;
  background: #f9f8f8;
  border: 1px solid #f1f1f1;
  box-shadow: 0 3px 8px -5px rgba(0, 0, 0, 0.8);
  display: none;
}
.sub-menu.nav-show {
  display: block;
}
.sub-menu > li {
  list-style: none;
  display: block;
  text-align: center;
}
.sub-menu > li:not(:first-child) {
  border-top: 1px solid #f1f1f1;
}
.sub-menu > li > a {
  text-decoration: none;
  display: block;
  font: 0.9em Arial, sans-serif;
  color: #9c9c9f;
  padding: 1em 0;
}
.sub-menu > li > a:hover {
  background: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="menu">
  <li><a href="" onclick="return false">Home</a>
  </li>
  <li class="drop-down"><a href="" onclick="return false">Projects</a>
    <ul class="sub-menu">
      <li><a href="/">HTML</a>
      </li>
      <li><a href="/">CSS3</a>
      </li>
      <li><a href="/">JavaScript</a>
      </li>
      <li><a href="/">PHP</a>
      </li>
    </ul>
  </li>
  <li><a href="" onclick="return false">Forums</a>
  </li>
  <li><a href="" onclick="return false">Blog</a>
  </li>
</ul>