Matthew Pichola
Matthew Pichola

Reputation: 77

Close subnav once a different subnav is open with jQuery

Currently I have this working almost perfectly, but the user has the ability to open multiple sub-nav's at once, and I need any open sub-nav's to close when another one is open.

Basically, the jQuery that's beloe, I need to classes to be removed if a new sub-nav is clicked on, currently it only removes them if the same one is clicked.

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"); 
});

Upvotes: 1

Views: 134

Answers (3)

epascarello
epascarello

Reputation: 207557

You can use siblings and select the elements with the class and remove them.

$("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>

Upvotes: 1

ShaneSauce
ShaneSauce

Reputation: 221

Could be done with removeClass

$(".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"); 
});

And you could clean up your code even more by using 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"); 
});

EDIT: Per @epascarello, This could also be made more performant by storing the subnav so it's not queried for twice:

$(".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"); 
});

Upvotes: 1

Metalgear
Metalgear

Reputation: 3457

How about this one? You should remove class 'open-sub' from all of 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"); 
});

Upvotes: 1

Related Questions