Home > Blockchain >  How to close a dropdown menu when another one is opening
How to close a dropdown menu when another one is opening

Time:09-21

I can't figure out how to close one submenu when another one is open. I'm not sure if html is needed here, so I'm just attaching JS code here:

problem demonstration

const burgerBtn = document.querySelector(".header__burger"),
  menu = document.querySelector(".menu"),
  body = document.querySelector(".body"),
  filter = document.querySelector(".filter"),
  blockFilter = document.querySelectorAll(".block-filter"),
  dropdown = document.querySelectorAll(".block-filter__dropdown");

if (filter) {
  blockFilter.forEach(item => {
    item.addEventListener("click", event => {
      item.querySelector(".block-filter__dropdown").classList.toggle("block-filter__dropdown_state_active");
      item.querySelector(".block-filter__icon").classList.toggle("block-filter__icon_state_active");
      if (event.target.classList.contains("block-filter__item")) {
        item.querySelector(".block-filter__value").textContent = event.target.textContent;
      }
    })
  })
}
<div >
  <form >
    <div >
      <div >
        <div >
          <span >Purpose</span>
          <div ></div>
        </div>
        <span >Buy</span>
      </div>
      <div >
        <span >Buy</span>
        <span >Sell</span>
      </div>
    </div>

CodePudding user response:

Sure, just remove the class from the active one first:

item.addEventListener("click", (event) => {
    // get active, and if it exists, remove active
    document.querySelector(".block-filter__dropdown_state_active")?.classList.remove("block-filter__dropdown_state_active");

    item.querySelector(".block-filter__dropdown").classList.toggle(
        "block-filter__dropdown_state_active"
    );
    item.querySelector(".block-filter__icon").classList.toggle(
        "block-filter__icon_state_active"
    );
    if (event.target.classList.contains("block-filter__item")) {
        item.querySelector(".block-filter__value").textContent =
            event.target.textContent;
    }
});

We use ?. here to prevent us from going further (and causing an error) if there is no active dropdown already.

CodePudding user response:

What you need to do is look for a currently active item first and "de-activate" them. You should also check that the currently active item is not the clicked item as you already have logic defined for that.

I've expanded on your snippet to create a solution.

NOTE: It might be useful creating a separate function/s for handling to "activate" and "de-activate" code where you pass in a .block-filter element.

const burgerBtn = document.querySelector(".header__burger"),
  menu = document.querySelector(".menu"),
  body = document.querySelector(".body"),
  filter = document.querySelector(".filter"),
  blockFilter = document.querySelectorAll(".block-filter"),
  dropdown = document.querySelectorAll(".block-filter__dropdown");

if (filter) {
  blockFilter.forEach(item => {
    item.addEventListener("click", event => {
      const active_dropdown = document.querySelector(".block-filter__dropdown_state_active");
      
      if(active_dropdown !== null){
          // get parent until we find ".block-filter"
          const active_item = active_dropdown.closest(".block-filter");
          // check it's not the current item
          if(active_item !== null && active_item !== item){
              // apply same logic as below to remove active state
              active_item.querySelector(".block-filter__dropdown").classList.remove("block-filter__dropdown_state_active");
              active_item.querySelector(".block-filter__icon").classList.remove("block-filter__icon_state_active");
          }
      }
      
      // your original logic
      item.querySelector(".block-filter__dropdown").classList.toggle("block-filter__dropdown_state_active");
      item.querySelector(".block-filter__icon").classList.toggle("block-filter__icon_state_active");
      if (event.target.classList.contains("block-filter__item")) {
        item.querySelector(".block-filter__value").textContent = event.target.textContent;
      }
    })
  })
}
/* base styles */
* {
  box-sizing: border-box;
}

html {
  font-family: sans-serif;
  background-color: #f3f3f3;
}


.filter.hero__filter {
  width:600px;
  margin:auto;
  border: 2px solid #eee;
  background-color: #fff;
}

.filter__form {
  display:flex;
}

.filter__block {
  flex: 1;
  padding: 5px;
  position: relative;
}

.block-filter__header {
  font-weight:600;
  font-size:12px;
  color: #555;
}

.block-filter__dropdown {
  display:none;
  position:absolute;
  top:100%;
  left:0;
  right:0;
  background-color:#fff;
  border: 1px solid #ccc;
  box-shadow: 0 2px 4px rgb(0 0 0 / 10%);
  border-radius:4px;
}

.block-filter__dropdown_state_active {
  display: block;
}

.block-filter__item {
  padding: 5px 10px;
  display:block;
  border-bottom: 1px solid #eee;
}

.block-filter__item:last-child {
  border-bottom: none;
}
<div >
  <form >
    <div >
      <div >
        <div >
          <span >Purpose</span>
          <div ></div>
        </div>
        <span >Buy</span>
      </div>
      <div >
        <span >Buy</span>
        <span >Sell</span>
      </div>
    </div>
    <div >
      <div >
        <div >
          <span >Second</span>
          <div ></div>
        </div>
        <span >Alpha</span>
      </div>
      <div >
        <span >Bravo</span>
        <span >Charlie</span>
        <span >Delta</span>
      </div>
    </div>
  </form>
</div>

  • Related