Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

jQuery Toggle Navigation Problem

See Code on Codepen:- http://codepen.io/saide4bd/pen/bdGNZx

Problem is when Click on DropDown menu 1 after another without closing first one second one shows correctly but first one not closing automatically how I can enable automatic closing when I click both of them I want to show only one of my dropdown at a time not both of my dropdown

3 Answers

Sean T. Unwin
Sean T. Unwin
28,690 Points

I did it this way. It's a little more specific than geoffry's although there is more code.

  jQuery(".navbar li").click(function(){

    // Select only those which have dropdown, but not the one clicked
    var $subs = jQuery(".navbar li li").parent().parent().not(jQuery(this));

    // Loop through each of the other dropdowns
    $subs.each(function() {
      // Check for visibility
      if (jQuery(this).children('ul').is(':visible')) {
        // close it
        jQuery(this).children('ul').slideUp();
      }
    })

    jQuery(this).children("ul").slideToggle();
  });

Codepen Example


But Wait There's More

Saidul Islam then asked:

If I want to hide this sub-menu when I click on other content of a page. How I can do this?

We can remove our previous jQuery(".navbar li").click() handler and replace with a document click handler. This is so it will be easy to detect click events outside as well as inside the menu.

The dropdown code from our previous click handler has been refactored to include easier to understand variable declarations as well as using the loop index ([i]) to select the current element within the loop instead of $(this). It is changed because this will be the click event's target, which in this case will be an anchor tag, so it's easier and less confusing this way, at least to me, as we don't have to traverse the DOM so much.

A concern with using the loop's index as part of the selector is that the selection is inside a jQuery object, as opposed to being one -- it is the raw element now. To handle this we need to encase the selection back into a jQuery object in order to use jQuery functions on it.

// Our variable $dropdown when used with
// loop's index value exposes the raw HTML element

// Is an array of elements inside a jQuery object
$dropdown = jQuery(".navbar-nav ul");

// Is a raw HTML element ( ul )
$dropdown[0]

// In order to use jQuery functions on the element
// we need to encase it with a jQuery object
jQuery($dropdown)

As an added bonus I have added a routine to close the entire mobile menu if it is open while a click event is outside of the menu. This is placed at the end so that we can still close dropdowns if they are open before the menu closes.

 /**
  * - Close any dropdowns that are open
  * - Toggle dropdown if it is clicked
  * - Close menu if open while clicked element
  *    is outside of menu
  **/
  // Somewhere in the document there is a click
  jQuery(document).on('click', function(evt) {

    // Select any dropdowns
    var $dropdown = jQuery(".navbar-nav ul");
    // Select anchor tag of dropdowns
    var $dropdownHitTarget = $dropdown.prev();

    // Loop through array of dropdowns
    $dropdownHitTarget.each(function(i) {

      // Clicked element is not current dropdown anchor
      if (evt.target !== $dropdownHitTarget[i]) {

        // Dropdown is visible
        if (jQuery($dropdown[i]).is(':visible')) {
          // Close it
          jQuery($dropdown[i]).slideUp();

        }
      // Clicked element matches current dropdown anchor
      } else {

        // Toggle open state of clicked dropdown
        jQuery($dropdown[i]).slideToggle();          
      }

    });

    // Menu is open
    // Click event is outside of menu
    if (jQuery('.navbar-collapse').hasClass('in') && jQuery('.navbar-nav').has(evt.target).length === 0) {

        // Close menu using menu button click event
        jQuery('.navbar-toggle').click();

    }

  });

Codepen Example

sorry to bother you If I want to hide this sub-menu when I click on other content of a page. How I can do this?

Sean T. Unwin
Sean T. Unwin
28,690 Points

Good question.

I have edited my answer to include one way how to do this.

Thanks buddy, you are really awesome

geoffrey
geoffrey
28,736 Points

Hi, I forked your codepen. Here is the way I did it.

    jQuery(".navbar li").click(function(){
                jQuery(".navbar li").not(this).children("ul").slideUp(); /* I added this line */
                jQuery(this).children("ul").slideToggle();
    });

Here is the link to my pen

Thanks both of you both code worked perfectly :)