Juggling both open and closed menus within a personalized accordion navigation

Check out this basic accordion-style menu: http://jsfiddle.net/JqJce/1/

<ul class="nav level-1">
    <li><a href="#">Link</a></li>
    <li class="has-submenu"><a href="#">Link</a>
    <ul class="level-2">
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
    </ul></li>
    <li class="has-submenu"><a href="#">Link</a>
    <ul class="level-2">
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
        <li class="has-submenu"><a href="#">Link</a>
        <ul class="level-3">
            <li><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
        </ul></li>
    </ul></li>
    <li class="has-submenu"><a href="#">Link</a>
    <ul class="level-2">
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
    </ul></li>
</ul>
a {
    display:block;
    background:#aaa;
    border:1px solid #ccc;
    padding:5px;
    color:#fff;
}
li li {
    display:none;
}

/* Open/Closed indicators */
.has-submenu > a:after {
 content:' + ';
}
.has-submenu .nav-open:after {
 content:' - ';
}

li li a {
   padding-left:40px;
    background:#888;
}
li li li a {
   padding-left:80px;
    background:#333;
}

This is what needs to happen:

  • Clicking on a link with a submenu should make the submenu slide down
  • If an open submenu's link is clicked again, it should collapse
  • Only one top-level submenu should be visible at a time (showing multiple "level 2" or "level 3" menus simultaneously is fine)
  • Closed menus should display +, while open menus should display -
  • The HTML markup cannot be changed, unfortunately

Current implementation:

$('.has-submenu > a').on('click', function(e){

    e.preventDefault();

    $(this).toggleClass('nav-open');

    $(this).next('ul').find('> li').slideToggle();

});

The above code successfully opens and closes menus. However, I'm struggling to close other level-1 menus when a new one is opened and change the icon accordingly. I've been trying to solve this for a while but can't seem to find the solution. Any help would be greatly appreciated!

Can someone assist? Feel free to ask if you need more information. http://jsfiddle.net/JqJce/1/

Answer №1

Here is a method:

$('.has-submenu > a').on('click', function (e) {
    e.preventDefault();

    // Check for currently open submenu and close it unless clicking on already open menu
    if ($(this).closest('.nav-open').length === 0)
    {
        $('.nav > .nav-open').removeClass('nav-open').find('> ul > li').slideUp();
    }

    // Add "nav-open" class to the <li> element, then toggle the slide animation for grandchildren <li>
    $(this).parent().toggleClass('nav-open').find('> ul > li').slideToggle();
});

http://jsfiddle.net/JqJce/6/

I am applying the nav-open class to the parent <li> of the <a>, not directly on the <a> itself

Additionally, I have made updates to this CSS:

.nav-open > a:after {
    content:' - ';
}

Answer №2

After numerous attempts and errors, I managed to figure it out for you.

Check out the solution here

$('.has-submenu > a').on('click', function(e){

    e.preventDefault();

    $(this).next('ul').find('> li').slideToggle();

    // Check if it's a level one link & there are other open links...
    if($(this).parent("li").parent("ul").hasClass("level-1") && $(".level-1 > li > a").hasClass("nav-open")) {
        //... collapse the top level open link.
        $(".level-1 > li > a.nav-open").next('ul').find('> ').slideToggle();
        $(".level-1 > li > a.nav-open").removeClass("nav-open");
    }

    $(this).toggleClass('nav-open');
});

I'm sure there must be a more efficient way to handle this problem, but both of our brains are probably fried by now! Best of luck!

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

How can we assign priority to the child element for detection by the "mouseover" event in jQuery?

Can you help me figure out how to make the "mouseover" event prioritize detecting the child element over its parent? This is the jQuery code I've been using: <script> $(function() { $("li").mouseover(function(event){ $('#log&a ...

Tips for incorporating HTML elements into XML emails

I'm facing an issue with my email template where the body of the email is being pulled as a String, resulting in raw html appearing in the email. Does anyone know how to insert an html tag into the body of an XML email using a String? <body> ...

Guide to adding customized CSS and JavaScript to a specific CMS page on Magento

I'm trying to incorporate a lightbox for video playback on a specific page of my CMS. I've placed my CSS file in JS/MY THEME/JQUERY/PLUGIN/VENOBOX/CSS/myfile.css and the JS files in JS/MY THEME/jquery/plugins/venobox/js/myfile.js, but it doesn&ap ...

Is it possible to utilize HTML as a platform for interfacing with a C/C++ program?

As I work on a new product with USB interface, I need to create a control app for it. However, my GUI programming skills are limited, so I have thought of using a local web page within the app's installation directory as the interface for the program. ...

PHP - Utilize get_option to send styling options to style.php

I'm having trouble figuring out how to structure my question, but in my plugin folder I have 2 files: 1 - "index.php" add_action( 'wp_enqueue_scripts', 'register_plugin_styles' ); function my_admin_setting() { include(' ...

AJAX method denied due to server restrictions

Pathway Route::put('path/update',['as'=>'test.update', 'uses'=>'TestController@update']); Ajax Request $.ajax({ url: 'path/update', type: 'PUT', dataType: 'json& ...

Unable to delete a dynamically inserted <select> element by using the removeChild method

As someone who is new to coding web applications, I am currently working on a project that involves adding and deleting dropdowns dynamically. Unfortunately, I have run into an issue where the delete function does not work when the button is pressed. Her ...

Incorporate a personalized array into Google Autocomplete Places using AngularJS

I'm working on my application and I've implemented autocomplete for Google Places using the gm-places-autocomplete directive. However, I would like to enhance this autocomplete feature by incorporating my custom array of locations along with the ...

Can GET or POST variables be transmitted to external JavaScript?

Is it possible to pass a variable to an external JavaScript file? For instance: Suppose I have the following code: <script type="text/javascript" src="gallery.js"></script> I'm curious to know if it's feasible to pass an argument ...

Tips for creating a dynamic div height that adjusts based on its content in percentage

Having trouble with 100% height sections that don't expand with the content? I've tried using height: auto; min-height: 100%; without success. Check out this FIDDLE for more information. ...

Updating checkbox Icon in Yii2

Is there a way to customize the checkbox icon when it is checked in Yii2? Currently, I am adding a checkbox inside a div along with an icon: <i class="fa fa-check-circle icon-check-circle"></i>. However, the checkbox shows a default check symbo ...

Prevent overlapping of range sliders in HTML and CSS

I have designed a range slider with two buttons, but they are overlapping each other. I want to ensure that they do not cross over one another - where the value of the first button should be equal to the minimum value of the second button, and the maximum ...

fixed footer with fixed height on parent container

I have successfully implemented a sticky footer on my web pages by following specific instructions. http://css-tricks.com/snippets/css/sticky-footer/ The recommended approach includes using min-height:100% and not specifying the height property. .page-w ...

Differences Between Data Captured from Form Submissions and Data Obtained Through Ajax

When attempting to incorporate reCAPTCHA into my MVC site, I encountered an issue where it would not validate unless submitted from a form. Here is the current implementation: @using(Html.BeginForm("VerifyCaptcha", "Signup") ) { @ReCaptch ...

What is the best way to add a directional hover effect to a filter?

I am attempting to implement a sliding hover filter effect on an image. The original filter I have is set to grayscale(1). What I want to achieve is for the filter to transition directionally instead of having a slider overlay effect, in order to change i ...

Is it possible to retrieve a variable from code.gs and pass it to my html file?

I had originally set up an automated email system to trigger once a certain condition was met, which I successfully implemented. However, I now want to enhance the email by including a more structured format and embedding an image from Google Drive. While ...

Show an SVG overlay when hovering over an image

Is there a way to create a hexagon shape around an image when it is hovered over using CSS only, even if the image itself has a circular border-radius of 50%? ...

Using the CSS :not selector to style certain input elements

Is there a way to style ALL input elements except for specific types without using the :not selector? Here's an example of what I tried: input, input:not(type='email') { background: red; } Unfortunately, this approach didn't work ...

Setting up or modifying JQuery AJAX encoding settings

I am currently working on a simple PATCH call similar to the one below: .ajax({ url: "/foo/bar/" type: "PATCH", dataType: 'json', data: { "foo": "foosball", "bar": "bars on bars" }, ... }); After Jquery e ...

Fit the image to fill the available space and position it in the center for maximum impact

I'm currently working on a single page application where I need to display an image that fills up as much available space as possible: Priority: maintain the aspect ratio Avoid cropping the image Stretch the image horizontally and/or vertically (with ...