Snorlax
Snorlax

Reputation: 293

Javascript - Remove class with document.addEventListener not working

I'm trying to close dropdown menu by clicking on the body or whatever. To do this I'm using document.addEventListener but it doesn't work.

By doing several tests I managed to get the code to work by adding a div that simulates a "body". So instead of document.addEventListener I wrote document.getElementById ("container_test"). AddEventListener.

the problem is that when there is no getElement it doesn't work. I can't understand what I'm wrong, can someone help me?

Here are two examples:

Not Working Code

var usermenu = document.querySelector(".user_menu_button");

function userMenu() {
  var x = document.getElementById("mts_menu");
  if (x.classList.toggle("show")) {
    usermenu.innerHTML = '<i class="icn_button fa-solid fa-xmark"></i><span class="txt_button">Account</span>';
  } else {
    usermenu.innerHTML = '<i class="icn_button fa-solid fa-bars"></i><span class="txt_button">Account</span>';
  }
}

const closing = document.querySelector("#mts_menu");

document.addEventListener("click", (evt) => {
  if (!evt.target.closest("#mts_menu")) closing.classList.remove("show");
});
/*Button Toggle Menu*/

.user_menu_button {
  display: flex;
  align-content: center;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 32px;
  background: #3D4350!important;
  border-radius: 4px;
  padding: 12px;
  font-size: 14px!important;
  line-height: 2;
}

.icn_button {
  margin: 0;
}

.icn_button:before,
.icn_button:after {
  margin: 0;
}

.txt_button {
  margin-left: 10px;
  color: #fff;
  font-size: 14px;
  font-weight: 400;
}


/*Items menu*/

.user_menu {
  display: flex;
  flex-direction: column;
}

.user_menu.header {
  padding: 15px 15px;
}


/*Menu header info*/

.display.name {
  font-size: 14px;
  font-weight: 500;
  color: #303238;
  line-height: 1.5;
}

.display.mail {
  font-size: 13px;
  color: #1E70EB;
  line-height: 1.5;
}

hr.divider-menu {
  border-top: 1px solid #e0e0e0;
}


/*Text Link css*/

.mnu_margin {
  margin: 7px 0;
}

.user_menu.item>a {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  padding: 8px 15px;
  color: #212629;
}

.user_menu.item:hover>a {
  color: #fff;
  background: #1E70EB;
  transition: all 0.2s;
}

.user_menu.item>a .link_text {
  font-size: 14px;
  color: #212629;
}

.user_menu.item:hover>a .link_text {
  color: #fff;
}


/*Icon Items Menu*/

.icn_menu:before,
.icon_menu:after {
  margin: 0px;
  padding: 0px;
  font-size: 16px
}

.icn_menu {
  margin-right: 10px;
  display: flex !important;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
}


/* User Menu For header website */

.mts_menu_container {
  display: flex;
  flex-direction: column;
  align-content: flex-end;
  align-items: flex-end;
}

.dropdown_box {
  position: absolute;
  margin-top: 20px;
}

.mts_dropdown_content {
  background-color: #fff;
  min-width: 160px;
  width: 240px;
  border-radius: 6px;
  overflow-x: hidden;
  overflow-y: hidden;
  box-shadow: rgba(0, 0, 0, 0.15) 0px 5px 15px 0px;
  z-index: 999;
  position: relative;
  visibility: hidden;
  opacity: 0;
  top: 50px;
  height: 0;
  transition: visibility 0.2s, max-height 0.2s, opacity 0.2s, top 0.2s, height 0.2s;
}

.mts_dropdown_content.show {
  height: 100%;
  visibility: visible;
  opacity: 1;
  top: 0;
  transition: visibility 0.2s, max-height 0.2s, opacity 0.2s, top 0.2s, height 0.2s;
}
<button onclick="userMenu()" class="user_menu_button">
     <i class="icn_button fa-solid fa-bars"></i>
     <span class="txt_button">Account</span>
</button>

<div class="mts_menu_container">
  <div class="dropdown_box">

    <div id="mts_menu" class="mts_dropdown_content">
      <div class="user_menu header">
        <span class="display name">Ciao [display_name]</span>
        <span class="display mail">[display_email]</span>
      </div>

      <hr class="divider-menu">

      <div class="mnu_margin">
        <div class="user_menu item">
          <a href="/account">
            <i class="icn_menu fa-regular fa-user"></i>
            <span class="link_text">Dashboard</span>
          </a>
        </div>

        <div class="user_menu item">
          <a href="ordini">
            <i class="icn_menu fa-regular fa-basket-shopping"></i>
            <span class="link_text">I miei ordini</span>
          </a>
        </div>

        <div class="user_menu item">
          <a href="libreria">
            <i class="icn_menu fa-regular fa-cloud-arrow-down"></i>
            <span class="link_text">Downloads</span>
          </a>
        </div>

        <div class="user_menu item">
          <a href="impostazioni">
            <i class="icn_menu fa-regular fa-gear"></i>
            <span class="link_text">Impostazioni</span>
          </a>
        </div>

        <div class="user_menu item last">
          <a href="wp-login.php?action=logout">
            <i class="icn_menu fa-regular fa-arrow-right-from-bracket"></i>
            <span class="link_text">Logout</span>
          </a>
        </div>
      </div>

    </div>
  </div>
</div>

Working Code

var usermenu = document.querySelector(".user_menu_button");

function userMenu() {
  var x = document.getElementById("mts_menu");
  if (x.classList.toggle("show")) {
    usermenu.innerHTML = '<i class="icn_button fa-solid fa-xmark"></i><span class="txt_button">Account</span>';
  } else {
    usermenu.innerHTML = '<i class="icn_button fa-solid fa-bars"></i><span class="txt_button">Account</span>';
  }
}

const closing = document.querySelector("#mts_menu");

document.getElementById("container_test").addEventListener("click", (evt) => {
  if (!evt.target.closest("#mts_menu")) closing.classList.remove("show");
});
#container_test {
  margin-top: 20px;
  border: 1px solid;
  padding: 20px;
}


/*Button Toggle Menu*/

.user_menu_button {
  display: flex;
  align-content: center;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 32px;
  background: #3D4350!important;
  border-radius: 4px;
  padding: 12px;
  font-size: 14px!important;
  line-height: 2;
}

.icn_button {
  margin: 0;
}

.icn_button:before,
.icn_button:after {
  margin: 0;
}

.txt_button {
  margin-left: 10px;
  color: #fff;
  font-size: 14px;
  font-weight: 400;
}


/*Items menu*/

.user_menu {
  display: flex;
  flex-direction: column;
}

.user_menu.header {
  padding: 15px 15px;
}


/*Menu header info*/

.display.name {
  font-size: 14px;
  font-weight: 500;
  color: #303238;
  line-height: 1.5;
}

.display.mail {
  font-size: 13px;
  color: #1E70EB;
  line-height: 1.5;
}

hr.divider-menu {
  border-top: 1px solid #e0e0e0;
}


/*Text Link css*/

.mnu_margin {
  margin: 7px 0;
}

.user_menu.item>a {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  padding: 8px 15px;
  color: #212629;
}

.user_menu.item:hover>a {
  color: #fff;
  background: #1E70EB;
  transition: all 0.2s;
}

.user_menu.item>a .link_text {
  font-size: 14px;
  color: #212629;
}

.user_menu.item:hover>a .link_text {
  color: #fff;
}


/*Icon Items Menu*/

.icn_menu:before,
.icon_menu:after {
  margin: 0px;
  padding: 0px;
  font-size: 16px
}

.icn_menu {
  margin-right: 10px;
  display: flex !important;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
}


/* User Menu For header website */

.mts_menu_container {
  display: flex;
  flex-direction: column;
  align-content: flex-end;
  align-items: flex-end;
}

.dropdown_box {
  position: absolute;
  margin-top: 20px;
}

.mts_dropdown_content {
  background-color: #fff;
  min-width: 160px;
  width: 240px;
  border-radius: 6px;
  overflow-x: hidden;
  overflow-y: hidden;
  box-shadow: rgba(0, 0, 0, 0.15) 0px 5px 15px 0px;
  z-index: 999;
  position: relative;
  visibility: hidden;
  opacity: 0;
  top: 50px;
  height: 0;
  transition: visibility 0.2s, max-height 0.2s, opacity 0.2s, top 0.2s, height 0.2s;
}

.mts_dropdown_content.show {
  height: 100%;
  visibility: visible;
  opacity: 1;
  top: 0;
  transition: visibility 0.2s, max-height 0.2s, opacity 0.2s, top 0.2s, height 0.2s;
}
<button onclick="userMenu()" class="user_menu_button">
     <i class="icn_button fa-solid fa-bars"></i>
     <span class="txt_button">Account</span>
</button>

<div class="mts_menu_container">
  <div class="dropdown_box">

    <div id="mts_menu" class="mts_dropdown_content">
      <div class="user_menu header">
        <span class="display name">Ciao [display_name]</span>
        <span class="display mail">[display_email]</span>
      </div>

      <hr class="divider-menu">

      <div class="mnu_margin">
        <div class="user_menu item">
          <a href="/account">
            <i class="icn_menu fa-regular fa-user"></i>
            <span class="link_text">Dashboard</span>
          </a>
        </div>

        <div class="user_menu item">
          <a href="ordini">
            <i class="icn_menu fa-regular fa-basket-shopping"></i>
            <span class="link_text">I miei ordini</span>
          </a>
        </div>

        <div class="user_menu item">
          <a href="libreria">
            <i class="icn_menu fa-regular fa-cloud-arrow-down"></i>
            <span class="link_text">Downloads</span>
          </a>
        </div>

        <div class="user_menu item">
          <a href="impostazioni">
            <i class="icn_menu fa-regular fa-gear"></i>
            <span class="link_text">Impostazioni</span>
          </a>
        </div>

        <div class="user_menu item last">
          <a href="wp-login.php?action=logout">
            <i class="icn_menu fa-regular fa-arrow-right-from-bracket"></i>
            <span class="link_text">Logout</span>
          </a>
        </div>
      </div>

    </div>
  </div>
</div>

<div id="container_test">container test</div>

Upvotes: 0

Views: 67

Answers (2)

Ahmed ALABSI
Ahmed ALABSI

Reputation: 21

  • In your "not working code" you need to exclude the button that show the menu too.
document.addEventListener("click", (evt) => {
      if (!evt.target.closest("#mts_menu")  && !evt.target.closest('.user_menu_button')) closing.classList.remove("show");
    });

Upvotes: 1

Barmar
Barmar

Reputation: 782130

When you click on the button to open the menu, the menu is opened, then the event bubbles out to document. Since the button isn't inside the menu, the menu closes.

Yuo should use event.stopPropagation in the button code to prevent this.

var usermenu = document.querySelector(".user_menu_button");

function userMenu(event) {
  event.stopPropagation();
  var x = document.getElementById("mts_menu");
  if (x.classList.toggle("show")) {
    usermenu.innerHTML = '<i class="icn_button fa-solid fa-xmark"></i><span class="txt_button">Account</span>';
  } else {
    usermenu.innerHTML = '<i class="icn_button fa-solid fa-bars"></i><span class="txt_button">Account</span>';
  }
}

const closing = document.querySelector("#mts_menu");

document.addEventListener("click", (evt) => {
  if (!evt.target.closest("#mts_menu")) closing.classList.remove("show");
});
/*Button Toggle Menu*/

.user_menu_button {
  display: flex;
  align-content: center;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 32px;
  background: #3D4350!important;
  border-radius: 4px;
  padding: 12px;
  font-size: 14px!important;
  line-height: 2;
}

.icn_button {
  margin: 0;
}

.icn_button:before,
.icn_button:after {
  margin: 0;
}

.txt_button {
  margin-left: 10px;
  color: #fff;
  font-size: 14px;
  font-weight: 400;
}


/*Items menu*/

.user_menu {
  display: flex;
  flex-direction: column;
}

.user_menu.header {
  padding: 15px 15px;
}


/*Menu header info*/

.display.name {
  font-size: 14px;
  font-weight: 500;
  color: #303238;
  line-height: 1.5;
}

.display.mail {
  font-size: 13px;
  color: #1E70EB;
  line-height: 1.5;
}

hr.divider-menu {
  border-top: 1px solid #e0e0e0;
}


/*Text Link css*/

.mnu_margin {
  margin: 7px 0;
}

.user_menu.item>a {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  padding: 8px 15px;
  color: #212629;
}

.user_menu.item:hover>a {
  color: #fff;
  background: #1E70EB;
  transition: all 0.2s;
}

.user_menu.item>a .link_text {
  font-size: 14px;
  color: #212629;
}

.user_menu.item:hover>a .link_text {
  color: #fff;
}


/*Icon Items Menu*/

.icn_menu:before,
.icon_menu:after {
  margin: 0px;
  padding: 0px;
  font-size: 16px
}

.icn_menu {
  margin-right: 10px;
  display: flex !important;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
}


/* User Menu For header website */

.mts_menu_container {
  display: flex;
  flex-direction: column;
  align-content: flex-end;
  align-items: flex-end;
}

.dropdown_box {
  position: absolute;
  margin-top: 20px;
}

.mts_dropdown_content {
  background-color: #fff;
  min-width: 160px;
  width: 240px;
  border-radius: 6px;
  overflow-x: hidden;
  overflow-y: hidden;
  box-shadow: rgba(0, 0, 0, 0.15) 0px 5px 15px 0px;
  z-index: 999;
  position: relative;
  visibility: hidden;
  opacity: 0;
  top: 50px;
  height: 0;
  transition: visibility 0.2s, max-height 0.2s, opacity 0.2s, top 0.2s, height 0.2s;
}

.mts_dropdown_content.show {
  height: 100%;
  visibility: visible;
  opacity: 1;
  top: 0;
  transition: visibility 0.2s, max-height 0.2s, opacity 0.2s, top 0.2s, height 0.2s;
}
<button onclick="userMenu(event)" class="user_menu_button">
     <i class="icn_button fa-solid fa-bars"></i>
     <span class="txt_button">Account</span>
</button>

<div class="mts_menu_container">
  <div class="dropdown_box">

    <div id="mts_menu" class="mts_dropdown_content">
      <div class="user_menu header">
        <span class="display name">Ciao [display_name]</span>
        <span class="display mail">[display_email]</span>
      </div>

      <hr class="divider-menu">

      <div class="mnu_margin">
        <div class="user_menu item">
          <a href="/account">
            <i class="icn_menu fa-regular fa-user"></i>
            <span class="link_text">Dashboard</span>
          </a>
        </div>

        <div class="user_menu item">
          <a href="ordini">
            <i class="icn_menu fa-regular fa-basket-shopping"></i>
            <span class="link_text">I miei ordini</span>
          </a>
        </div>

        <div class="user_menu item">
          <a href="libreria">
            <i class="icn_menu fa-regular fa-cloud-arrow-down"></i>
            <span class="link_text">Downloads</span>
          </a>
        </div>

        <div class="user_menu item">
          <a href="impostazioni">
            <i class="icn_menu fa-regular fa-gear"></i>
            <span class="link_text">Impostazioni</span>
          </a>
        </div>

        <div class="user_menu item last">
          <a href="wp-login.php?action=logout">
            <i class="icn_menu fa-regular fa-arrow-right-from-bracket"></i>
            <span class="link_text">Logout</span>
          </a>
        </div>
      </div>

    </div>
  </div>
</div>

Upvotes: 1

Related Questions