2

I have a header section which contains a submenu.

When a user click outside of header, I'm looking to hide the submenu.

For now, I'm simply trying to console.log when clicking anywhere except when clicking on the header.

I've seen similar articles on SO, however, they don't work in my instance.

My console.log's are still appearing when I click on the header?

$(function () {
  // $('html:not(.globalHeader)').click(function(event){
  //   event.stopPropagation();
  //   console.log("click");
  // });

  $("body")
    .not(".globalHeader")
    .on("click", function (e) {
      e.preventDefault();
      console.log("click");
    });
});
header {
  padding: 20px 0;
  background: black;
  color: white;
  text-align: center;
}

.spacer {
  height: 100vh;
  background: lightblue;
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" integrity="sha512-aVKKRRi/Q/YV+4mjoKBsE4x3H+BkegoM/em46NNlCqNTmUYADjBbeNefNxYV7giUp0VxICtqdrbqU7iVaeZNXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<body>
  <header class="globalHeader">Header</header>
  <div class="spacer">Spacer</div>
</body>
Freddy
  • 683
  • 4
  • 35
  • 114
  • i suggest you rather listen to the `mouseout` event on the `header` element, and then when that happens just hide the header, its easier to do it this way – Dean Van Greunen Oct 13 '22 at 13:47
  • `$("body").not(".globalHeader")` is *all body elements that don't have class globalHeader* - it's unlikely you have `` so this is just `$("body")`. You *might* have tried `$("body *").not(".globalHeader")` but that will add a click event to *every* element (except globalHeader), including those inside globalHeader, so, apart from the load, also not what you want. – freedomn-m Oct 13 '22 at 15:41

1 Answers1

1
  1. By doing $('body').not('.globalHeader') this returns the body element and adds the click event to it, so any inner element will trigger the click event, you need to filter out the header, so see #2
  2. I switched to using the overload of .on and setting the 2nd parameter to :not(.globalHeader) and it works as intended, this adds a filter to the click event on the body and becomes a delegated event jQuery.on

EDIT:

  1. I added to my answer to modify the callback function to check for descendants of the header and return false if it's a descendant and also added a sample span for testing purposes.

$(function () {
    $('body').on("click", ":not(.globalHeader)", function (e) {
       e.preventDefault();

       //check to see if this is a descendant of the header
       if($(this).closest('.globalHeader').length)
           return false;

       console.log("click");
    });
});
header {
   padding: 20px 0;
   background: black;
   color: white;
   text-align: center;
   cursor: pointer;
}

.spacer {
   height: 100vh;
   background: lightblue;
   display: flex;
   justify-content: center;
   align-items: center;
   margin-top: 10px;
}
  .globalHeader > span:hover {
      cursor: pointer;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" integrity="sha512-aVKKRRi/Q/YV+4mjoKBsE4x3H+BkegoM/em46NNlCqNTmUYADjBbeNefNxYV7giUp0VxICtqdrbqU7iVaeZNXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

 <body>
    <header class="globalHeader">Header<br/><span>Click Me I'm A Header Child</span></header>
    <div class="spacer">Spacer</div>
 </body>
Ryan Wilson
  • 10,223
  • 2
  • 21
  • 40
  • I think this will fail if you click on a child of `.globalHeader`, you might want to check for `.closest()` – DBS Oct 13 '22 at 13:55