Question

I want to toggle the next sibling of a link in a list like this,

<ul>
    <li><a href="#">1</a></li>
    <li><a href="#">2</a>
        <ul class="selected">
            <li><a href="#">2.1</a></li>
            <li><a href="#">2.2</a></li>
            <li><a href="#">2.3</a></li>
        </ul>
    </li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a>
        <ul class="selected">
            <li><a href="#">4.1</a></li>
            <li><a href="#">4.2</a></li>
            <li><a href="#">4.3</a></li>
        </ul>
    </li>
    <li><a href="#">5</a></li>
</ul>

and this is my jquery,

$(document).ready(function(){

    $("a").each(function () {
        if ( $(this).siblings().size() > 0) 
        {
            $(this).append("<span class='has-child'>has child</span>");

            $(this).toggle(
                function (){
                    $("ul").removeClass("showme");
                    $(this).siblings(".selected").addClass("showme");
                    //$(this).next().css({display: "block"});
                },
                function (){
                    $(this).siblings(".selected").removeClass("showme");
                    //$(this).next().css({display: "none"});
            });

        }
    });

    $('ul > li > ul > li:last-child > a').css('background','yellow');

});

the css,

ul > li > ul {
        display:none;
    }

    ul > li:hover ul{
        display: block;
    }
    .showme {
        display: block;
    }

first of all, it seems fine - I can toggle the targeted sibling, but why after the first toggle at any parent, I have to click twice sometime to hide other siblings when I click/ toggle at the current parent?

here is the live site if I am not explaining it clearly, http://lauthiamkok.net/tmp/jquery/toggle/

Many thanks, Lau

Was it helpful?

Solution

Instead of a .toggle() function which is ending up in the wrong state you ca just use a normal click function and use .toggleClass() instead, like this:

$(this).click(function (){
  var myUL = $(this).siblings(".selected").toggleClass("showme");
  $("ul").not(myUL).removeClass("showme");
});

You can give it a try here, this does a .toggleClass() on the sibling, then looks for all other <ul> elements, by filtering out the sibling with .not().

This cleans up a bit making it easier, the main issue it resolves is the non-exclusion of the sibling from .removeClass(), this is what caused your .toggle() state to be incorrect before.

OTHER TIPS

See the modified function. Just one change and it will work fine.

$("a").each(function () {
    if ( $(this).siblings().size() > 0) 
    {
        $(this).append("<span class='has-child'>has child</span>");

        $(this).toggle(
            function (){
                // $("ul").removeClass("showme"); Change this
                $(this).next("ul").removeClass("showme");
                $(this).siblings(".selected").addClass("showme");
                return false;
                //$(this).next().css({display: "block"});
            },
            function (){
                $(this).siblings(".selected").removeClass("showme");
                return false;
                //$(this).next().css({display: "none"});
        });

    }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top