Ben Racicot
Ben Racicot

Reputation: 5951

Nested navigation click logic issue

I've been trying to get a simple vertical navigation to display a list item's children on click.

However when you then click any of those nested, children list items you are in essence 'clicking' the parent list item again. Which triggers my click function to remove '.active' and closes the parent list item right before the user is redirected to their chosen page. This looks bad and is totally annoying.

Any advice on how to get a click function to not affect the children list items?

$('#sidebar > li.parent').click(function(){
  if($(this).hasClass('active')){
        $(this).removeClass('active');
      }else{
        $(this).addClass('active');
  }
});

HTML

<aside id="tertiary" class="tertiary">
    <ul id="sidebar" class="sidebar">
        <li class="active"><a href="/">Portal</a></li>
        <li><a href="ecards.html">Start Here</a></li>
        <li><a href="ecards.html">Cards</a></li>
        <li class="parent"><a href="programs.html">Programs</a>
            <ul>
                <li><a href="#">LOS</a></li>
                <li><a href="#">Safety</a></li>
                <li><a href="#">Retirement</a></li>
                <li><a href="#">Wellness</a></li>
                <li><a href="#">Investors</a></li>
            </ul>
        </li>
        <li><a href="#">Marketplace</a></li>
        <li><a href="#">Reporting</a></li>
    </ul>
</aside>

Upvotes: 1

Views: 126

Answers (3)

chazsolo
chazsolo

Reputation: 8484

Before you stop propagation of events, take some time to spin up on why you shouldn't do so.

From css-tricks.com, "The Dangers of Stopping Event Propagation", very briefly:

"Modifying a single, fleeting event might seem harmless at first, but it comes with risks. When you alter the behavior that people expect and that other code depends on, you're going to have bugs. It's just a matter of time."

"A much better solution is to have a single event handler whose logic is fully encapsulated and whose sole responsibility is to determine whether or not the menu should be hidden for the given event."

With that being said, you could do something like

$('#sidebar').on('click', function( e ) {
    var $target = $(e.target).closest('li');

    if ( $target.hasClass('parent') ) {
        $target.toggleClass('active');
    }
});

Working example: http://jsfiddle.net/g6a496Lf/1/

Upvotes: 1

joews
joews

Reputation: 30330

You could add a click handler for the child elements that uses stopPropagationto prevent the click event bubbling to parent elements:

$('#sidebar > li li').click(function(e){
  e.stopPropagation();
});

Further reading: MDN docs for Event.

Upvotes: 2

iCollect.it Ltd
iCollect.it Ltd

Reputation: 93601

You would need to stop propagation in the children... not the parent

http://jsfiddle.net/TrueBlueAussie/g6a496Lf/

$('#sidebar > li.parent').click(function (e) {
    e.preventDefault();
    $(this).toggleClass('active');
}).find("ul li").click(function(e){
    e.stopPropagation();    
});

The e.preventDefault() is just there to stop the link clicking on the parent in the example. e.stopPropagation() stops the child click bubbling up the DOM.

I chained the two handlers together, so that you did not need a separate selector like this:

$('#sidebar > li.parent ul li").click(function(e){
    e.stopPropagation();    
});

Upvotes: 4

Related Questions