2

I am trying to create multilevel pure javascript menu with JS. BUt it only captures first element only.

(function() {
  
  document.querySelector('.more').addEventListener('click', function() {
    
    this.classList.toggle('open')
  }, false);
})();
li ul {display: none}
li.open ul {display: block}
<ul>
  <li>1</li>
  <li class="more">
    2
    <ul>
      <li>2,1</li>
      <li>2.2</li>
    </ul>
  </li>
  <li>2</li>
  <li>3</li>
  <li class="more">
    4
    <ul>
      <li>4.1</li>
      <li>4.2</li>
    </ul>
  </li>
  
</ul>
<ul>
  <li>1</li>
  <li class="more">
    2
    <ul>
      <li>2,1</li>
      <li>2.2</li>
    </ul>
  </li>
  <li>2</li>
  <li>3</li>
  <li class="more">
    4
    <ul>
      <li>4.1</li>
      <li>4.2</li>
    </ul>
  </li>
</ul>

When i tried to run query selector all it gives me an error saying querySelectorAll().addEventListener is not a function.

Can someone see what I am doing wrong here. Thanks.

Blundering Philosopher
  • 6,245
  • 2
  • 43
  • 59
vsoni
  • 497
  • 1
  • 7
  • 22

3 Answers3

1

Use querySelecrotAll in order to get array of elements and then loop through them individually to apply event listener.

https://www.w3schools.com/jsref/met_element_queryselectorall.asp

Adapted code:

   (function() {
      document.querySelectorAll('.more').forEach(element =>
        element.addEventListener('click', function() {

          this.classList.toggle('open')
        }, false)
      );
    })();
James Trickey
  • 1,322
  • 13
  • 21
1

document.querySelectorAll returns an array of elements.

You just need to loop through them (ex: with Array.forEach) and add your event listener to each expandable element like this:

(function() {
  // get all elements with class 'more'
  let expandableElem = document.querySelectorAll('.more');
  
  // loop through each expandable element, adding click listener
  expandableElem.forEach(li => {
    li.addEventListener(
      'click',
      function() {
        this.classList.toggle('open')
      },
      false
    )
  });
})();
li ul {display: none}
li.open ul {display: block}
<ul>
  <li>1</li>
  <li class="more">
    2
    <ul>
      <li>2,1</li>
      <li>2.2</li>
    </ul>
  </li>
  <li>2</li>
  <li>3</li>
  <li class="more">
    4
    <ul>
      <li>4.1</li>
      <li>4.2</li>
    </ul>
  </li>
  
</ul>
Blundering Philosopher
  • 6,245
  • 2
  • 43
  • 59
0

The document.querySelectorAll is what you are looking for to select all .more elements. After that, use 'forEach' or a 'for' loop to add the EventListener on each .more element.

<ul class="nav">
  <li>1</li>
  <li class="more">2
    <ul>
      <li>2,1</li>
      <li>2.2</li>
    </ul>
  </li>
  <li>3</li>
  <li>4</li>
  <li class="more">5
    <ul>
      <li>5.1</li>
      <li>5.2</li>
    </ul>
  </li>
</ul>

<script>
(function() {
  var elm = document.querySelectorAll('.more');
  for (var i=0; i< elm.length; i++) {
    elm[i].addEventListener('click', function() {
      // optional 'remove' other elm's
      this.classList.toggle('open');
    }, false);
  }
})();
</script>

with some minimal css

.nav, .nav ul {
    margin: 0;
    padding: 0;
    list-style: none;
}
.nav {
    position: relative;
    z-index: 597;
    float: left;
}
.nav ul {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 598;
    min-width: 150px;
}
.nav .open ul {
    display: block;
}
.nav li {
    position: relative;
    cursor: pointer;
    padding: 4px 10px;
}
.nav > li {
    float: left;
}
.nav ul li {
    float: none;
}
bron
  • 1,457
  • 1
  • 9
  • 18