1

I have a simple Javascript-enabled Wordpress menu plugin that I've built myself.

It has a top level menu that works fine and a sub-menu dropdown that doesn't. For some reason, only the first (top) submenu dropdown onclick function works as expected - the rest don't work at all. It seems like it's a CSS targeting issue, but I don't see how it can be, when I look at the code.

As I say, the code works as expected on the first li -just not the rest.

I'd love to know what I've done wrong

The JS is as follows:

const hamburger = document.querySelector(".hamburger");
const navMenu = document.querySelector(".nav-menu");

hamburger.addEventListener("click", mobileMenu);

function mobileMenu() {
    hamburger.classList.toggle("active");
    navMenu.classList.toggle("active");
}

const triangle = document.querySelector(".menu-hide-me");
const subMenu = document.querySelector(".sub-menu");

triangle.addEventListener("click", giveclasstosubmenu);

function giveclasstosubmenu() {
    triangle.classList.toggle("sub-open");
    subMenu.classList.toggle("sub-open");
}

The HTML for the menu is:

<div class="navbar"\>

    <div class="nav-menu">
        <?php wp_nav_menu( array(
            'menu' => 'mobile',
            'link_before' => '<span class="menu-item">',
            'link_after' => '</span>',
            'after' => '<span class="dropdownClick"><img class="menu-hide-me" src="...down-arrow-menu.png"></span>'
             )
        );?>
    </div>
    
    <div class="hamburger">
        <span class="bar"></span>
        <span class="bar"></span>
        <span class="bar"></span>
    </div>
    
</div><!------end navbar------------>

Here's the CSS

/**------------------- sub-menu stuff------------------------**/
    
    /**hides all dropdown arrows except for li with sub menu items**/
    
    .menu-hide-me {
        display:none;
    }   
    
    .menu-item span {
        color: #c9e1d1!important;
    }
    
    .menu-item-has-children .menu-hide-me {
        display: inline;
        width: 11px;
        margin-left: 10px;
    }
    
        
    .sub-menu li .menu-hide-me {
        display:none;
    }
    
    
        
    /**hides sub-menu**/
    .sub-menu {
        display:none;
    }
    

    /**open sub-menu**/
    .sub-menu.sub-open {
        display:block;
        padding-left: 10px;
    }
    
    
    /**styling for links**/ 
    
    .sub-menu li {
        line-height:1.5!important;
    }
    
    .sub-menu a {
        color: #c9e1d1;
        font-size: 13px;
    }
2
  • 1
    querySelector returns one single element (or null, if not found.) If you want to select multiple elements, you need to use querySelectorAll instead. (And then iterate over the elements in the resulting NodeList, if you want to do stuff such as assign individual event handlers.) Commented Oct 17 at 12:02
  • Just tried querySelectorAll and that made none of it work. How would you suggest iterating over the elements? Thanks for the reply by the way Commented Oct 17 at 12:14

1 Answer 1

4

The issue is happening because you’re only selecting the first .menu-hide-me and .sub-menu in your JavaScript:

const triangle = document.querySelector(".menu-hide-me");

const subMenu = document.querySelector(".sub-menu");

document.querySelector() only returns the first matching element.
So your click event and submenu toggle work for that first one, but not for the others.

To fix this, you need to select all the .menu-hide-me elements and then attach the event listener to each one individually, making sure to toggle only the corresponding submenu.

Here’s how you can fix it:

const hamburger = document.querySelector(".hamburger");
const navMenu = document.querySelector(".nav-menu");

hamburger.addEventListener("click", mobileMenu);

function mobileMenu() {
    hamburger.classList.toggle("active");
    navMenu.classList.toggle("active");
}

// Select all triangles
const triangles = document.querySelectorAll(".menu-hide-me");

triangles.forEach(triangle => {
    triangle.addEventListener("click", () => {
        // Find the closest parent <li> that has the submenu
        const parentLi = triangle.closest("li");
        const subMenu = parentLi.querySelector(".sub-menu");

        if (subMenu) {
            triangle.classList.toggle("sub-open");
            subMenu.classList.toggle("sub-open");
        }
    });
});
  • querySelectorAll() grabs every .menu-hide-me.

  • For each arrow (triangle), we find its own parent <li> that contains the related .sub-menu.

  • Then we toggle the sub-open class on both that triangle and that submenu, not on the first one in the DOM.

This ensures each dropdown works independently.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Younis - that's done it. Thanks C3ROE too - the theory stuff was very useful too. It's good to know where your thinking goes wrong sometimes
You Welcome Fran!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.