title: How to prevent the same event registering on ancestor elements when Event.stopPropagation doesn't work?
body: <p>I have an expandable menu with nested submenus to an infinite depth.</p>
  
  <pre><code>&lt;ul&gt;
      &lt;li&gt;One&lt;/li&gt;
      &lt;li class="contains-submenu"&gt;Two
          &lt;ul&gt;
              &lt;li&gt;Two A&lt;/li&gt;
              &lt;li class="contains-submenu"&gt;Two B
                  &lt;ul&gt;
                      &lt;li&gt;Two B I&lt;/li&gt;
                      &lt;li&gt;Two B II&lt;/li&gt;
                      &lt;li&gt;Two B III&lt;/li&gt;
                  &lt;/ul&gt;
              &lt;/li&gt;
              &lt;li&gt;Two C&lt;/li&gt;
          &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Three&lt;/li&gt;
      &lt;li class="contains-submenu"&gt;Four
          &lt;ul&gt;
              &lt;li&gt;Four A&lt;/li&gt;
              &lt;li class="contains-submenu"&gt;Four B
                  &lt;ul&gt;
                      &lt;li&gt;Four B I&lt;/li&gt;
                      &lt;li&gt;Four B II&lt;/li&gt;
                      &lt;li&gt;Four B III&lt;/li&gt;
                  &lt;/ul&gt;
              &lt;/li&gt;
              &lt;li&gt;Four C&lt;/li&gt;
          &lt;/ul&gt;
      &lt;/li&gt;
  &lt;/ul&gt;
  </code></pre>
  
  <p>I want to show / hide any sub-menu at any level, without influencing the show / hide status of any other sub-menu and <em>especially not</em> the show / hide status of <strong><em>any ancestor</em></strong> of the sub-menu.</p>
  
  <p>What I found initially was that if I used a <code>click</code> event listener to toggle a class <code>.show-submenu</code> to show or hide a submenu, when a submenu lower down (e.g. <strong>Two B</strong>) was closed, then its parent, the submenu <strong>Two</strong>, would <em>also close</em>.</p>
  
  <p>It became apparent that this was happening because at almost the same moment I was clicking on <strong>Two B</strong>, a click event was also registering on <strong>Two</strong> (...of course it was - <strong>Two B</strong> is nested <em>inside</em> <strong>Two</strong> - any click on <strong>Two B</strong> will also register as a click on <strong>Two</strong>).</p>
  
  <p>I tried to fix this using <code>.stopPropagation()</code>... but then I realised that actually this <em>wasn't</em> (at least I don't think it was) a case of a single event registering on two different elements as the event bubbled up through <strong>Two</strong> from <strong>Two B</strong>, but <em>two different events</em> registering, one on <strong>Two</strong> almost immediately after the other on <strong>Two B</strong>.</p>
  
  <p>My solution was the following:</p>
  
  <pre><code>var activateToggle = true;
  
  function toggleSubmenu() {
      if (activateToggle === true) {
          this.classList.toggle('show-submenu');
          activateToggle = false;
      }
  
      setTimeout(function(){activateToggle = true}, 100);
  }
  </code></pre>
  
  <p>Is this a reasonable approach to produce the desired effect?</p>
  
  <p>Or is there a more conventional approach using <code>event.target</code> or similar?</p>
  
  <p><strong>Complete Working Example:</strong></p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var querySelector = 'ul &gt; li &gt; ul';
  var selectedElements = [... document.querySelectorAll(querySelector)];
  var activateToggle = true;
  var initialPadding = 6;
  var subsequentPadding = 18;
  var level = 0;
  
  
  while (selectedElements.length &gt; 0) {
  
      for (var j = 0; j &lt; selectedElements.length; j++) {
          selectedElements[j].parentNode.classList.add('contains-submenu');
          selectedElements[j].style.marginLeft = (0 - (initialPadding + (level * subsequentPadding))) + 'px';
          [... selectedElements[j].children].forEach(function(childElement){
              childElement.style.paddingLeft = (initialPadding + ((level + 1) * subsequentPadding)) + 'px';
          });
      }
  
      level++;
      querySelector += ' &gt; li &gt; ul';
      selectedElements = [... document.querySelectorAll(querySelector)];
  }
  
  var containsSubmenus = document.getElementsByClassName('contains-submenu');
  
  
  function toggleSubmenu() {
      if (activateToggle === true) {
          this.classList.toggle('show-submenu');
          activateToggle = false;
      }
  
      setTimeout(function(){activateToggle = true}, 100);
  }
  
  
  for (let i = 0; i &lt; containsSubmenus.length; i++) {
      containsSubmenus[i].addEventListener('click', toggleSubmenu, false);
  }</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>ul {
  margin-left: 0;
  padding-left: 0;
  font-family: arial, helvetica, sans-serif;
  color: rgb(255, 255, 255);
  background-color: rgba(0, 75, 165, 1);
  list-style-type: none;
  }
  
  li {
  padding-left: 6px;
  font-size: 16px;
  line-height: 32px;
  }
  
  ul ul {
  display: none;
  }
  
  .show-submenu &gt; ul {
  display: block;
  }
  
  li.show-submenu {
  height: auto;
  }
  
  .contains-submenu {
  font-weight: 700;
  cursor: pointer;
  }
  
  .contains-submenu ul {
  font-weight: 300;
  cursor: default;
  }
  .contains-submenu,
  .contains-submenu ul {
  background-color: rgba(255, 255, 255, 0.1);
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;ul&gt;
      &lt;li&gt;One&lt;/li&gt;
      &lt;li class="contains-submenu"&gt;Two
          &lt;ul&gt;
              &lt;li&gt;Two A&lt;/li&gt;
              &lt;li class="contains-submenu"&gt;Two B
                  &lt;ul&gt;
                      &lt;li&gt;Two B I&lt;/li&gt;
                      &lt;li&gt;Two B II&lt;/li&gt;
                      &lt;li&gt;Two B III&lt;/li&gt;
                  &lt;/ul&gt;
              &lt;/li&gt;
              &lt;li&gt;Two C&lt;/li&gt;
          &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Three&lt;/li&gt;
      &lt;li class="contains-submenu"&gt;Four
          &lt;ul&gt;
              &lt;li&gt;Four A&lt;/li&gt;
              &lt;li class="contains-submenu"&gt;Four B
                  &lt;ul&gt;
                      &lt;li&gt;Four B I&lt;/li&gt;
                      &lt;li&gt;Four B II&lt;/li&gt;
                      &lt;li&gt;Four B III&lt;/li&gt;
                  &lt;/ul&gt;
              &lt;/li&gt;
              &lt;li&gt;Four C&lt;/li&gt;
          &lt;/ul&gt;
      &lt;/li&gt;
  &lt;/ul&gt;</code></pre>
  </div>
  </div>
  </p>