The functionality of submenu levels in Vanilla JS is not functioning as expected

I am currently developing a menu using Vanilla JavaScript for integration into an Angular 8 project. The functionality works well up to a certain point, as it successfully opens the hidden menus. However, I encountered an issue where attempting to open a second level hidden menu results in everything closing. For instance, clicking on the 'Soluciones' link opens the submenu smoothly. Yet, when attempting to click on 'Correo y herramientas' to reveal a second level hidden menu containing links such as Correo 1, Correo 2, and Correo 3, everything closes abruptly. You can view the codepen demonstration here: https://codepen.io/Bungo808/pen/ZEBpmXG Any insights or advice would be greatly appreciated!

My HTML


<div class="red">

    <nav id="nav" class="sub-menu open">
      <ul class="list-unstyled">
        <li id="subb">
          <a class="link">Quiénes somos</a>
          <img id="iplus" class="splus" src="../../assets/img/splus.svg" alt="">
          <ul id="smenu" >
            <li>
                <a class="link">Sobre eSource</a>
            </li>
            <li>
                <a class="link">Amarello</a>
            </li>
          </ul>
        </li>
        <li id="subb">
          <a class="link">Soluciones</a>
          <img id="iplus" class="splus" src="../../assets/img/splus.svg" alt="">
          <ul id="smenu" >
            <li id="subb">
                <a class="link">Correo y herramientas</a>
                <ul>
                    <li><a class="link">Correo 1</a></li>
                    <li><a class="link">Correo 2</a></li>
                    <li><a class="link">Correo 3</a></li>
                </ul>
            </li>
            <li id="subb">
                <a class="link">Infrastructure as a Service</a>
                <ul>
                    <li><a class="link">Infra 1</a></li>
                    <li><a class="link">Infra 2</a></li>
                    <li><a class="link">Infra 3</a></li>
                </ul>
            </li>
          </ul>
        </li>
    
      </ul>
    </nav>
    <div class="overlay"></div>
</div>

My JS

let list_items = document.querySelectorAll('#subb');

// Show Submenu
    for (let i = 0; i < list_items.length; i++) {
      list_items[i].addEventListener("click", show);
    }

    function show() {
      this.classList.toggle("myClass");
      console.log('I clicked it!')
    }


The relevant CSS responsible for opening the hidden menu is shown below:


.sub-menu {
  padding: 0 0 0 2%;
  left: 0px;
  top: 0;
  transition: all 0.3s ease;
  height: 100%;
  width: 280px;
  position: fixed;
  margin: 0;
  background-color: #f9f9f9;
  border-radius: 0;
  z-index: 10;
  overflow: hidden;
}

.sub-menu > ul {
  width: 100%;
  height: 100%;
  margin-top: 60px;
}
.sub-menu li {
  position: relative;
  display: block;
  list-style: none;
  padding: 2px 0 2px 14px;
  margin-left: 0;
  cursor: pointer;
  color: white;
  transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  &:first-child{
    // border: 1px solid red;
  }
}
.sub-menu li a {
  color: #40465f;
  font-size: 16px;
  font-weight: 300;
  width: 100%;
  display: block;
  line-height: 22px;
  padding: 6px 0;
  &:hover{
    color: #2487FC;
    text-decoration: none;
  }
}
.sub-menu ul ul li a {
  color: #40465f;
  font-size: 14px;
  font-weight: 300;
  width: 100%;
  line-height: 22px;
  padding: 6px 0;
  &:hover{
    color: #2487FC;
    text-decoration: none;
  }
}
.sub-menu ul ul ul li a {
  color: #40465f;
  font-size: 14px;
  font-weight: 300;
  width: 100%;
  display: block;
  line-height: 22px;
  padding: 6px 0;
  &:hover{
    color: #2487FC;
    text-decoration: none;
  }
}

.sub-menu ul ul{
  display: none;
  background: white;
}

#subb.myClass > ul{
  display: block;
}

.sub-menu ul ul ul{
  display: none;
  border: 1px solid red;
}

Answer №1

Every time the click event occurs, it continues to propagate repeatedly. This causes the class to be toggled off eventually. To avoid this issue, simply include .stopPropagation(); in your show() function as shown below:

function show(e) {
  e.stopPropagation();
  this.classList.toggle("myClass");
  console.log('I clicked it!')
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encountered an error of 'No overload matches this call' while configuring ContextApi alongside useReducer with Typescript

I am currently setting up ContextApi and useReducer with typescript. I am encountering an error with my "issuesInitialState" variable in useReducer, where I receive the following message: No overload matches this call. Overload 1 of 5, '(reducer: ({ ...

What is the best way to make a ContentPlaceHolder in ASP.NET expand to cover the entire page?

I am facing an issue with my Master page and some of the pages that use it. Despite having insufficient content on one or two pages, the footer ends up appearing near the middle of the screen and the background becomes visible at the bottom. I am looking f ...

Having trouble with JavaScript's XMLHttpRequest returning an 'undefined' string on the first run of my script. I need to find a way to ensure that it loads correctly during

Before we dive in, a quick disclaimer: My knowledge of JS is limited, and I typically learn on the go when creating scripts. However, my usual method didn't work this time. Currently, I'm working on a small JS script that will function as a book ...

Tips for accessing the selected dropdown value in a different React component

I am new to React and I have a dropdown that allows me to select different languages that I want to share with all my components. However, I am having trouble achieving this. I have tried using localStorage and Context, but whenever I change the value, I c ...

Adjust regex for image URLs in JavaScript to handle unique and special cases

Does anyone have experience with using image URL regular expressions to validate images in forms with the ng-pattern directive? I'm currently facing difficulties handling cases like https://google.com.png. Any assistance would be greatly appreciated. ...

sendResponse' was not located

chrome.runtime.onMessage.addListener( function(props) { switch(props.request_type) { case 'msg': websocketClass.msgSubmit(props.data) break; case 'url': websocketClass.msgSubmit(props.data) break; case 'his': sendResponse({his ...

Getting child objects from an imported model in Three.js

I need help accessing a specific child mesh from a 3D model I imported that contains multiple child objects. Despite using .getObjectByName("Cylinder", true), I keep receiving undefined even though the model does have a child object with that name: https ...

What is the best way to utilize ng-if to conceal a component in AngularJS when a button in a separate component is clicked?

I am facing a challenge with two child components within a parent component. My goal is to hide component1 when a button in component2 is clicked. Below is an illustration of the current code I am handling: Parent Component HTML: <div ng-app='ap ...

Tips on applying a transition to a v-dialog with "dynamic width" and utilizing width="unset"

Currently, I am in the process of developing a form component enclosed within a v-dialog. This particular form component will consist of various child components that are displayed based on user input selection. In order to ensure that the dialog width adj ...

How can I send various maximum values to the Backbone template?

Although in theory, it may seem simple, I am unsure about the exact code to use. In a view, if I define a variable max that retrieves an attribute called points from a collection, I can pass this variable as an object into my template using maxPoints.toJS ...

Tips on customizing default Polymer CSS

Currently, the core-toolbar features an indent class that shifts the title to the right by 60px. However, material design guidelines suggest that the margin should actually be 80px (oddly enough, the number 60 is not mentioned in the documentation). I cou ...

Turn off scrolling for the body content without removing the scrollbar visibility

Whenever I click a thumbnail, a div overlay box appears on top: .view-overlay { display:none; position:fixed; top:0; left:0; right:0; bottom:0; overflow-y:scroll; background-color:rgba(0,0,0,0.7); z-index:999; } Some browsers with non-f ...

difficulties encountered while inserting a script tag linking to a local file within an android webview

I have created an Android app with a simple WebView that loads a local HTML file from the assets folder in the project directory. The HTML file includes a tag that makes an AJAX call to an external service and expects a response in the form of a String re ...

Where should custom PHP code be placed in Prestashop 1.7.5?

Currently, I am facing the challenge of incorporating a custom PHP code snippet into Prestashop's file structure so that it is accessible on all pages such as the cart, categories, and CMS pages. After some research, I have found suggestions to place ...

Styling with CSS: Proper alignment of elements within a div container

I'm struggling with positioning three elements within a div. The left element needs to be on the left, the middle element centered, and the right element on the right. Here's what I have so far in my CSS: #left-element { margin-left: 9px; ...

What is the best way to dynamically change the JSON-LD Script for the Schema?

Below is the script in question. Please read through it carefully. <script type="application/ld+json"> { "@context": "http://schema.org/", "@type": "Product", "name": "Bat, &q ...

Adding checkboxes to a list within HTML/Django: A step-by-step guide

I am currently working on a django/html project where I need to allow users to delete multiple rows in a data table. To achieve this, I've decided to implement checkboxes within a list. For each item, I can add: <tr> <td><input type=" ...

Can anyone point me to the Angular-2-Release that is located on the https://code.angularjs.org

Word has it that angular 2 has finally made its debut. Personally, I'm not a big fan of relying on npm and bower to automatically load my components. I prefer to keep my dependencies minimal and fully understand each one. Additionally, I like to utili ...

"Concealing a div based on the toggling of another one - here's

Currently, I have a scenario where clicking on an image inside a div triggers the display of another div while simultaneously wanting to hide the original div containing the image. So far, utilizing only the abreInfo() function achieves the desired toggle ...

Retrieving a json file via Ajax, then showcasing the data with radio buttons

Json file called services.json: { "0": "Dog", "1": "Cat", "2": "Pony" } Html form with radio buttons for Dog, Cat, and Pony: <form class="form-horizontal"> <div class="form-group" id="radiobuttongroup"> ...