jQuery can be used to automatically close a subnav when another subnav is opened

Currently, my code is almost perfect, but there is a slight issue with allowing multiple sub-navs to be open at the same time. I want to ensure that when one sub-nav is opened, any others automatically close.

Essentially, in the jQuery code below, I need to modify it so that if a new sub-nav is clicked on, any other open ones will close. Currently, it only closes the same sub-nav if clicked again.

HTML

<nav class="st-menu" id="menu-4a">
    <ul>
        <li>
            <a href="#">Guidance Manual</a>
        </li>
        <li>
            <a href="#">Resource Directory</a><div class="toggle-arrow"><img src="/assets/images/chevron-up-solid.svg"/></div>
            <ul class="reg-subnav">
                <li><a href="#">Stormwater Plan Review Resources</a></li>
                <li><a href="#">Pilot Projects</a></li>
                <li><a href="#">Proprietary Products</a></li>
                <li><a href="#">Additional Resources</a></li>
            </ul>
        </li>
        <li>
            <a href="#">Stormwater 101</a><div class="toggle-arrow"><img src="/assets/images/chevron-up-solid.svg"/></div>
            <ul class="reg-subnav">
                <li><a href="#">Regulations</a></li>
                <li><a href="#">Stormwater Management</a></li>
                <li><a href="#">Stormwater Billing & Retrofits</a></li>
                <li><a href="#">Green City, Clean Waters</a></li>
            </ul>
        </li>
        <li>
            <a href="#">Contact Us</a><div class="toggle-arrow"><img src="/assets/images/chevron-up-solid.svg"/></div>
            <ul class="reg-subnav">
                <li><a href="#">About Us</a></li>
                <li><a href="#">Development Review Contacts</a></li>
            </ul>
        </li>
    </ul>
</nav>

jQuery

$(".toggle-arrow").click(function(){
    $(this).closest('li').find(".reg-subnav").toggleClass('open-sub');
    $(this).closest('li').find('.arrow-image').toggleClass("flip"); 
});

Answer №1

Utilize siblings to select and remove elements with the specified class.

$("nav").on("click", ".toggle-arrow", function(){
    var currentLi = $(this).closest('li')
    currentLi.find(".reg-subnav").toggleClass('open-sub');
    currentLi.find('.toggle-arrow').toggleClass("flip");
    
    //clean up the other open elements
    var otherLis = currentLi.siblings()
    otherLis.find(".open-sub").removeClass('open-sub')
    otherLis.find(".flip").removeClass('flip')

});
.reg-subnav {
  display: none;
}

.reg-subnav.open-sub {
  display: block;
}

img {
 width: 20px;
}

.toggle-arrow {
  position: relative;
  cursor: pointer;
  display: inline-block;
}

.toggle-arrow img {
  transform: rotateX(180deg);
  transition: transform 0.75s;
  transform-style: preserve-3d;
}

.toggle-arrow.flip img {
  transform: rotateY(0deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav class="st-menu" id="menu-4a">
    <ul>
        <li>
            <a href="#">Guidance Manual</a>
        </li>
        <li>
            <a href="#">Resource Directory</a><div class="toggle-arrow"><img src="https://image.flaticon.com/icons/svg/120/120906.svg"/></div>
            <ul class="reg-subnav">
                <li><a href="#">Stormwater Plan Review Resources</a></li>
                <li><a href="#">Pilot Projects</a></li>
                <li><a href="#">Proprietary Products</a></li>
                <li><a href="#">Additional Resources</a></li>
            </ul>
        </li>
        <li>
            <a href="#">Stormwater 101</a><div class="toggle-arrow"><img src="https://image.flaticon.com/icons/svg/120/120906.svg"/></div>
            <ul class="reg-subnav">
                <li><a href="#">Regulations</a></li>
                <li><a href="#">Stormwater Management</a></li>
                <li><a href="#">Stormwater Billing & Retrofits</a></li>
                <li><a href="#">Green City, Clean Waters</a></li>
            </ul>
        </li>
        <li>
            <a href="#">Contact Us</a><div class="toggle-arrow"><img src="https://image.flaticon.com/icons/svg/120/120906.svg"/></div>
            <ul class="reg-subnav">
                <li><a href="#">About Us</a></li>
                <li><a href="#">Development Review Contacts</a></li>
            </ul>
        </li>
    </ul>
</nav>

Answer №2

What do you think about this suggestion? It is recommended to delete the 'open-sub' class from all lists.

$(".toggle-arrow").click(function(){
    $("nav.st-menu").find(".reg-subnav").removeClass('open-sub');
    $(this).closest('li').find(".reg-subnav").toggleClass('open-sub');

    $("nav.st-menu").find(".arrow-image").removeClass('flip');
    $(this).closest('li').find('.arrow-image').toggleClass("flip"); 
});

Answer №3

One way to achieve this is by using the removeClass method.

$(".toggle-arrow").click(function(){
    $(".reg-subnav").not($(this).closest("li").find(".reg-subnav")).removeClass("open-sub");
    $(this).closest('li').find(".reg-subnav").toggleClass('open-sub');
    $(this).closest('li').find('.arrow-image').toggleClass("flip"); 
});

You can make your code more concise by utilizing the siblings selector:

$(".toggle-arrow").click(function(){
    $(".reg-subnav").not($(this).siblings(".reg-subnav")).removeClass("open-sub");
    $(this).siblings(".reg-subnav").toggleClass('open-sub');
    $(this).siblings('.arrow-image').toggleClass("flip"); 
});

UPDATE: As recommended by @epascarello, you can optimize performance by storing the subnav and avoiding redundant queries:

$(".toggle-arrow").click(function(){
    var $thisSubnav = $(this).siblings(".reg-subnav");
    $(".reg-subnav").not($thisSubnav).removeClass("open-sub");
    $thisSubnav.toggleClass('open-sub');
    $(this).siblings('.arrow-image').toggleClass("flip"); 
});

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

Use 'data-toggle='button'' in Angular component only once the condition is validated

Looking to verify a certain condition upon clicking, and if it evaluates to true, toggle the element that was clicked <div class="btn-group btn-group-toggle" data-toggle="buttons"> <label class="btn btn-secondary active" (click)='example ...

What is the technique to transfer the value from collection_select to the onchange method in Rails?

In my task, I need to extract the selected value from the collection_select drop-down menu and pass it to an onchange function. However, when I access the "name" attribute, the printed value is source[index]. Instead, I want to retrieve the actual value ...

The functionality of jQuery click events seems to be disabled on the webpage, however, it is working perfectly fine on jsFiddle

After thoroughly checking the js tags and ensuring everything is properly closed, it's frustrating when the JavaScript suddenly stops working. The code functions perfectly in JSFiddle, leading me to believe that the issue may lie with something I&apos ...

LESS: Using variable values in mixin and variable names

I am looking to simplify the process of generating icons from svg-files while also creating a png-sprite fallback for IE8 support. I am using grunt.js and less. I was inspired by the implementation on 2gis.ru: (in Russian), where they used technologies s ...

Ways to apply CSS styles dynamically within a v-for loop

Despite searching through the VUE official website and various other sources, I have not been able to find a satisfactory solution. I am reaching out for assistance, thank you in advance. <div class="tag-item" :ref="`tagItem_ ...

What is the best way to increase the padding in a Colorbox modal window?

Is there a way to increase the padding in a Colorbox modal window? I want some extra space between the edges of the modal window and the actual content. I experimented with the innerWidth and innerHeight properties, but unfortunately, I didn't notice ...

Ways to make text within a container smoothly slide down

Hello, I have a question about jQuery as I am relatively new to it. I am currently working on creating a team members section where clicking on a team member will slide down information about that person underneath. I have managed to set up the parent co ...

Creating code that adheres to the ECMAScript 5 standards

In my quest to create a JavaScript library that adheres to modern standards such as HTML5, CSS3, and ESv5, I find myself wanting to break away from the mainstream libraries like jQuery and MooTools. While these are great tools, I believe in the importance ...

JavaScript Tutorial: Extracting the text content of a drop event

Curious about extracting the text value from a drop event, I set out to find an answer. To my surprise, I discovered that it's not as straightforward as I thought. Check out the demo below: <script src="https://ajax.googleapis.com/ajax/libs/jquer ...

Effortlessly handle form submission with jQuery AJAX, automatically redirecting upon successful

I am working on a project using ASP.Net MVC where I have a view that submits form data to a controller action. In order to make this form submission more dynamic, I am trying to utilize jQuery to post the form via an AJAX call with the following code: $(" ...

What is the best way to make jQuery not consider hidden elements?

Apologies for not sharing the code, as I know many of you prefer to see it. I am currently working on developing a comprehensive calculator for my small business, and I am aware that I am making several mistakes. I kindly request that you do not critique ...

The page fails to load when redirected, however, it briefly displays the page upon clicking the back button before navigating back to the previous page

Currently, I am working with Angular 2 and encountering an issue when attempting to click on a link. The loading bar continues to progress without displaying the data or HTML content on the page. Furthermore, if I try to go back to the previous page, the i ...

Dynamically load select options using Ajax

I'm a newcomer to javascript and ajax, and I'm working on implementing Ajax to display the current category on my HTML select in a CodeIgniter project. Below is the code snippet: HTML: <select class="form-control" name="category" id="categor ...

Spinning and disappearing gradually over a set period of time

Could someone please help me with creating an animation for one of my CSS DIVs? I want it to have an exit/entry effect with rotation/fadeout and then rotation/fadein, with a 10-minute delay between each iteration. I'm not sure if this can be achieved ...

Guide to designing a CSS gradient with a downward arrow linked to a specific container

I'm attempting to add a triangular arrow beneath the v-container, complete with a gradient color scheme. However, I'm struggling to integrate the gradient seamlessly. If I use CSS to create the arrow, the gradient doesn't align correctly. ...

What is the best way to send a POST request to my Rails controller using Ajax?

I'm facing an issue trying to transmit data from my JavaScript game-state on the front end to my controller and ultimately store it in the database. Unfortunately, I haven't received any response so far, and I'm struggling to pinpoint the re ...

Fuzzy text in drop-down box on Chrome, clear on Firefox

I've encountered an issue with a dropdown menu in Google Chrome where the content appears blurry, while it displays correctly in Firefox. The problem arises when the dropdown exceeds a certain height, and I've tried setting a max-height with over ...

Identify and correct improper or invalid HTML closing tags in Visual Studio Code

As part of my transition to Visual Studio Code from Adobe Brackets, I am looking to replicate the feature that highlights incorrect close markup in my code. This feature is particularly helpful in identifying duplicated </div> tags like shown in the ...

Loading AJAX content with jQuery FancyBox after a delay

When a fancybox element is clicked in my app, I use AJAX to load an HTML page. However, on that remote page there is also some JavaScript logic that utilizes AJAX (yes, I know it's strange) to load data upon page load. Currently, I am trying to find a ...

How can I show hidden column names in the Sencha Touch 2 date picker component with CSS?

I am currently utilizing a date and time picker that has the ability to display ['month', 'day', 'year','hour','minute','ampm']. You can find the source code here. Although everything is function ...