0

I'm trying to make a simple slide down menu when the top level menu item is clicked. The functionality I'm looking for is when a top level menu item is clicked all other sub menus slides up and the one that is clicked slides down, and when you click the same menu item the sub menu slides up.

The problem I'm having is targeting the child ul tags

<ul>
  <li class="main-menu-item">
    <a href="#"></a>
    <ul class="sub-menu">
      <li>Stuff</li>
    </ul>
  </li>
</ul>

Here's my jQuery

(function( $ ) {
    'use strict';
    $(function() {

        var menuItem = $('#nav__menu li.main-menu-item'),
                subMenuItem = $('#nav__menu ul.sub-menu' );
        // setup
        menuItem.parents().attr('tabIndex',-1).attr('aria-haspopup',true);
        subMenuItem.attr('aria-hidden', true);

        menuItem.on('click', function(e) {
            e.preventDefault();
            $(this).toggleClass('active');
            $(this).siblings('.active').removeClass('active');
        });
        subMenuItem.each(function() {
            if($(this).parents().hasClass('active')) { 
          $(this).find(subMenuItem).attr('aria-hidden', false).slideDown();
        } else {
          $(this).find(subMenuItem).attr('aria-hidden', true).slideup(); 
        }
        });
    });
})( jQuery );

JS Fiddle

gilgimech
  • 21
  • 6
  • It would be helpful if you posted a live demo (jsfiddle or stack snippet) that includes all the code to recreate the problem! – Maximillian Laumeister Sep 21 '15 at 23:20
  • 1
    I would also like to point out that you should take the habit of [prepending your variable names with `$` if they store a jQuery object](http://stackoverflow.com/a/5754099/2788131). It helps readability (eg. `$menuItem` and `$subMenuItem`). – D4V1D Sep 21 '15 at 23:21
  • Maybe you could try one of the many examples available at [CSS Play](http://www.cssplay.co.uk/menus/). The site has a lot of options and most of the examples don't even need javascript / jquery to work. – Romulo Sep 21 '15 at 23:35
  • Thanks for the suggestion but it doesn't help me with this issue – gilgimech Sep 21 '15 at 23:52

2 Answers2

0

Your submenu code needs to be inside the click function of the menuItem code otherwise it'll execute just once on page load. You also have two DOM ready functions, and are selecting things more than once.

You don't need to define submenuitems on load then iterate through them all looking for which has the active parent. You use children() or find() for that.

https://jsfiddle.net/Lt34k1n3/2/

(function( $ ) {
    'use strict';
    $('#nav__menu li.main-menu-item') // select this once
        .attr('tabIndex',-1).attr('aria-haspopup',true) // apply attributes
        .find('ul.sub-menu') // find the child dropdown
            .attr('aria-hidden', true) // set attrs on that
            .slideUp() // and slide up
        .end() // go back up to #nav__menu li.main-menu-item
        .on('click', function(e) {
            e.preventDefault();
            $(this)
                .addClass('active') // remove active class
                .find('ul.sub-menu') // find child dd
                    .attr('aria-hidden', false)
                    .slideDown() // set attrs
                .end() // back up to $(this) which is still #nav__menu li.main-menu-item
                .siblings() // select its siblings
                    .removeClass('active')
                    .find('ul.sub-menu') // find these to close them
                        .attr('aria-hidden', true)
                        .slideUp()
        });

})( jQuery );

Should you want to toggle the clicked item, you would use slideToggle and toggleClass rather than slideDown and addClass, and you would need to create the boolean for the aria-hidden attribute which you can do by inverting the result for $(this).closest('ul.sub-menu').hasClass('active') which means 'does the ancestor "ul.sub-menu" have the class "active"?'

        $(this)
            .toggleClass('active')
            .find('ul.sub-menu')
                .attr('aria-hidden', !$(this).closest('ul.sub-menu').hasClass('active'))
                .slideToggle()
            .end()
Popnoodles
  • 28,090
  • 2
  • 45
  • 53
0

I found a pretty simple example that works for me.

(function( $ ) {
  'use strict';
    var $menuItem = $('#nav__menu li.menu-item-has-children'),
      $subMenuItem = $('#nav__menu ul.sub-menu' );
    // setup
    $menuItem.addClass('closed').attr('tabIndex',-1).attr('aria-haspopup',true);
    $subMenuItem.attr('aria-hidden', true);
    $($menuItem).on('click', function() {
        $(this).siblings('li').removeClass('open').addClass('closed').children('ul').hide();
        if($(this).hasClass('closed')){
            $(this).removeClass('closed').addClass('open');
            $(this).children('ul').slideDown();
        } else if($(this).hasClass('open')){
            $(this).removeClass('open').addClass('closed');
            $(this).children('ul').slideUp();
        }
    })
})( jQuery );

I hope this can help someone else

gilgimech
  • 21
  • 6
  • If `$menuItem` stores a jQuery object, there is no need for enclosing it with `$()` when using it. Therefore, `$($menuItem).on('click');` is pointless. Use `$menuItem.on('click')` directly (like you did with `$menuItem.addClass();`). – D4V1D Sep 22 '15 at 07:52