Search code examples
javascripthtmlcssindexingmenu

how do I close submenus submenu on main submenu parent click


I'm trying to close all submenus submenus when the submenus parent arrow element is clicked, and also rotate the arrows back. The statement that I've written does not work. it is supposed to toggle only the submenu submenus that match the Event Target. Please help. https://jsfiddle.net/d3auwqvb/



<!DOCTYPE html>

<head>
  <title>webpage</title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <html lang="en" dir="ltr" />
  <link rel="stylesheet" href="css/style.css" />
  <link rel='stylesheet' href="https://unpkg.com/[email protected]/css/boxicons.min.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" />
</head>

<body>
      <div class="index-list">
        <ul class="index-itself">
          <li class="indexitem1 indexitem"><a href="#">indexitem1</a><i class="fas fa-angle-down indexitem1indexarrow arrow"></i>
            <ul class="indexitem1submenu index-sub-menu hidden">
              <li class="indexitem2 indexitem"><a href="#">indexitem2</a><i class="fas fa-angle-down indexitem2indexarrow arrow"></i>
                <ul class="indexitem2submenu index-sub-menu-sub-menu hidden">
                  <li><a href="#">lorem uipson</a></li>
                </ul>
              </li>
            </ul>      
          </li>
          <li class="indexitem3 indexitem"><a href="#">indexitem3</a><i class="fas fa-angle-down indexitem1indexarrow arrow"></i>
            <ul class="indexitem3submenu index-sub-menu hidden">
              <li class="indexitem4 indexitem"><a href="#">indexitem4</a><i class="fas fa-angle-down indexitem2indexarrow arrow"></i>
                <ul class="indexitem4submenu index-sub-menu-sub-menu hidden">
                  <li><a href="#">lorem uipson</a></li>
                </ul>
              </li>
            </ul>      
          </li>
        </ul>
      </div>
      </body>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap');

.index-list {
  position: static;
  width: calc(100% - 50%);
word-wrap: break-word;
padding: 10px 20px;
text-align: left;
border: 3px solid #444;
margin: 0px 105px 100px 100px;
box-shadow: #333;
background-color: #ffffff;
font-family: poppins;
font-size: 17px;
}
.index-list li {
  list-style: none;
}
.index-list li a {
  text-decoration: none;
  color: #000;
}
.index-list li i {
  color: #000;
  cursor: pointer;
  font-size: 20px;
}
.index-list .index-itself .index-sub-menu li a {
  position: relative;
  padding-left: 10px;
}
.index-list li i:hover{
  font-size: 22px;
}
.hidden {
  display: none;
}
.rotatearrow {
  transform: rotate(180deg);
}


// Index //

const indexList = document.querySelector('.index-list');
const indexSubmenus = document.querySelectorAll('.index-sub-menu');
const indexSubmenusSubmenus = document.querySelectorAll('.index-sub-menu-sub-menu');

// close all submenu submenus and arrows on submenu arrow click //
indexSubmenus.forEach(submenu =>{
indexSubmenusSubmenus.forEach(submenuSubmenu =>{
submenu.parentElement.children[1].addEventListener('click',(Event)=>{
  if (submenuSubmenu.parentElement.parentElement == Event.target.parentElement){
  this.classList.add('hidden');
  this.parentElement.children[1].classList.remove('rotatearrow')}
    });
  });
});

//

// open submenus and submenu submenus //
openSubmenus = (Event)=>{
  for(let i=0; i < indexSubmenus.length; i++)
  if(indexSubmenus[i].parentElement.children[1] == Event.target){
    Event.target.parentElement.children[2].classList.toggle('hidden');
    Event.target.parentElement.children[1].classList.toggle('rotatearrow');
  }};
openSubmenusSubmenus = (Event)=>{
  for(let i=0; i < indexSubmenusSubmenus.length; i++)
  if(indexSubmenusSubmenus[i].parentElement.children[1] == Event.target){
    Event.target.parentElement.children[2].classList.toggle('hidden');
    Event.target.parentElement.children[1].classList.toggle('rotatearrow');
}};

indexList.addEventListener('click',openSubmenus);
indexList.addEventListener('click',openSubmenusSubmenus);

//

i tried this Javascript and this does not work:

indexSubmenus.forEach(submenu =>{
indexSubmenusSubmenus.forEach(submenuSubmenu =>{
submenu.parentElement.children[1].addEventListener('click',(Event)=>{
  if (submenuSubmenu.parentElement.parentElement === Event.target.parentElement){
  this.classList.add('hidden');
  this.parentElement.children[1].classList.remove('rotatearrow')}
    });
  });
});

Solution

  • Sorry I couldn't do it with preserving the class .hidden however the HTML attribute hidden has similar effects.

    So here is my solution:

    // Index //
    
    const indexList = document.querySelector('.index-list');
    const indexSubmenus = document.querySelectorAll('.index-sub-menu');
    const indexSubmenusSubmenus = document.querySelectorAll('.index-sub-menu-sub-menu');
    
    // close all submenu submenus and arrows on submenu arrow click //
    indexSubmenus.forEach(submenu => {
      indexSubmenusSubmenus.forEach(submenuSubmenu => {
        submenu.parentElement.children[1].addEventListener('click', (Event) => {
          if (submenuSubmenu.parentElement.parentElement == Event.target.parentElement) {
            this.setAttribute('hidden', '');
            this.parentElement.children[1].classList.remove('rotatearrow');
          }
        });
      });
    });
    
    //
    
    // open submenus and submenu submenus //
    openSubmenus = (Event) => {
      for (let i = 0; i < indexSubmenus.length; i++) {
        if (indexSubmenus[i].parentElement.children[1] == Event.target) {
          if (!Event.target.parentElement.children[2].children[0].children[2].hasAttribute('hidden')) {
                    Event.target.parentElement.children[2].children[0].children[2].setAttribute('hidden','')
            }
          if(Event.target.parentElement.children[2].hasAttribute('hidden')){
            Event.target.parentElement.children[2].removeAttribute('hidden');
          }
          else{
            Event.target.parentElement.children[2].setAttribute('hidden', '');
          }
          Event.target.parentElement.children[1].classList.toggle('rotatearrow');
    
        }
      }
    };
    openSubmenusSubmenus = (Event) => {
      for (let i = 0; i < indexSubmenusSubmenus.length; i++)
        if (indexSubmenusSubmenus[i].parentElement.children[1] == Event.target) {
          if(Event.target.parentElement.children[2].hasAttribute('hidden')){
            Event.target.parentElement.children[2].removeAttribute('hidden');
          }
          else{
            Event.target.parentElement.children[2].setAttribute('hidden','');
          }
          Event.target.parentElement.children[1].classList.toggle('rotatearrow');
        }
    };
    
    indexList.addEventListener('click', openSubmenus);
    indexList.addEventListener('click', openSubmenusSubmenus);
    

    The problem when I tried to do it with class .hidden was to identify the status whether it is active or not. I tried with hasAtrribute("class","hidden") but it didn't work (probably because the element has many classes). Someone may suggest how to do it. Unless you want to preserve .hidden, this code does what you asked for.

    Hope this solves your problem!