0

I'm building a mega menu that has a close button on each menu that works great. However I need to write some JavaScript that says, 'if you click outside a mega menu when it's open, close it'.

I've written a script below. It does detect when a user clicks inside of the mega menu, but it doesn't when they click outside of it. In this case, removing the display-on class which makes an element have display: block;.

const dropDownMenu = document.getElementsByClassName("drop-down");

for (let i = 0; i < dropDownMenu.length; i++) {
  dropDownMenu[i].addEventListener("click", (e) => {
    // If clicking in any area that has drop-down class, do nothing.
    if (dropDownMenu[i].contains(e.target)) {
      console.log("clicked in mega menu area");
      // If clicking in any area outside drop-down class, remove display-on class which closes the menu.
    } else {
      console.log("clicked outside mega menu area");
      document.querySelector(".display-on").classList.remove("display-on");
    }
  });
}

Working demo if needed can be seen here.

Thanks.

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
infused
  • 79
  • 10
  • 1
    Of cause the OP needs to register the handling of *"out of drop-down"* events also outside of any `drop-down` classified element. `document.body` might be the right element for listening. – Peter Seliger Nov 08 '21 at 17:16

2 Answers2

0

From the above comment ...

"Of cause the OP needs to register the handling of "out of drop-down" events also outside of any drop-down classified element. document.body might be the right element for listening."

... something like this ...

function handleDropDownMenuBehavior(evt) {
  if (evt.target.closest('.drop-down') === null) {

    document.querySelector(".display-on").classList.remove("display-on");

    console.log("clicked outside mega menu area");
  } else {
    console.log("clicked in or at mega menu area");
  }
}
document.body.addEventListener('click', handleDropDownMenuBehavior);
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
  • Tried this out and when I clicked on any of the dropdown parent links to show the menu, on that click it automatically removed the display-on class on the mega menu itself. Therefore the mega menu doesn't show, because the display-on class is stripped away rendering the menu not to show at all. Is there a way to only make the above code that you wrote happen AFTER the mega menu is open, and the user clicks away from the mega menu? – infused Nov 08 '21 at 19:14
  • @infused ... sure, if you provide the most necessary html and the css for it. For my above example all I've got from the original post's example code was the `drop-down` class name. You also need to provide the code wich actually triggers the display of a menu. – Peter Seliger Nov 08 '21 at 22:51
  • @infused ... still with us? – Peter Seliger Nov 12 '21 at 15:28
-1

You could add a global event listener to the document which checks if what was clicked on isn't the mega menu. let me know if you need any extra help :)

document.onclick = (e) => {
    if (e.target.contains(document.getElementsByClassName("drop-down")[0])) {
        console.log('close mega menu');
        document.getElementsByClassName("drop-down")[0].classList.remove("display-on");
    }
}
  • 1
    This does work, but only on the very first drop down item (in this case, the 'rental equipment' menu). But not any other mega menu. How can we make this work so it doesn't just affect the first item [0], but all mega menus? – infused Nov 08 '21 at 19:15
  • 1
    Figured it out! Added a for loop as I had to iterate through all of them, and then remove the `display-on` classes when the `display-on` element appeared: `document.onclick = (e) => { for (let i = 0; i < dropDownMenu.length; i++) { if (e.target.contains(dropDownMenu[i])) { document.querySelector(".display-on").classList.remove("display-on"); } } };` – infused Nov 08 '21 at 19:48