Hi, I am having some funny problems with hiding and showing the navigation and I am not entirely sure why. Here's the demo:
http://antobbo.webspace.virginmedia.com/various_tests/worktest/hidingnavigation/test.htm and here's the code:
html:

...
<!-- NAVIGATION -->
    <div id="navBox">
        <ul>
            <li class="mainList"><a href="#">Item 1</a>
                <ul class="subList">
                    <li><a href="#">sub item1.1</a></li>
                    <li><a href="#">sub item1.2</a></li>
                    <li><a href="#">sub item1.3</a></li>
                </ul>
            </li>
            <li class="mainList"><a href="#">Item 2</a>
                <ul class="subList">
                    <li><a href="#">sub item2.1</a></li>
                    <li><a href="#">sub item2.2</a></li>
                    <li><a href="#">sub item2.3</a></li>
                </ul>
            </li>
            <li class="mainList"><a href="#">Item 3</a>
                <ul class="subList">
                    <li><a href="#">sub item1.1</a></li>
                    <li><a href="#">sub item1.2</a></li>
                    <li><a href="#">sub item1.3</a></li>
                </ul>
            </li>
        </ul>
    </div>
    <!-- END OF NAVIGATION -->   
...

css:

#navBox{
    border:1px solid yellow;
    width:400px;
}

#navBox ul > li > ul{
    display:none;
}

and the script:

$(".mainList a").click(function(){

    $(this).find("ul").toggle();

    });

But it doesn't work, and I am not sure why. In the script I am targeting each link in a li item$(".mainList a"), assigning a click function then find the relevant ul and toggle it. But, alas, it doestn' work. What am I getting wrong please?

Recommended Answers

All 5 Replies

Hi, first thing, your script is loaded and executed at load time. This mean that when the script is run the DOM is not ready, so none of the objects that you are trying to add an handler to will exist. This means that the listeners are not attached.
To solve this, call your scripts at the load of the page. One way of doing it is:

//jQuery on DOM loaded event
$(function() {
    $(".mainList a").click(function(){
        $(this).find("ul").toggle();
    });
});

Another thing, the selector '.mainList a' will select all 'a' inside '.mainList'. This mean that all 'a', even in the sub-menus will be selected.

To select only the 'a' in the main list do as '.mainList > a' (will select only the 'a' that is directly bellow '.mainList').

Another thing, "$(this).find('ul')" will find nothing. Because $(this) is an '<a>' and there's nothing inside it to be found. An solution it's to use 'next' instead of 'find' (find only search inside the selected element, while 'next' search in the same level as the element)

Here's one example that should work fine:

//jQuery on DOM loaded event
$(function() {
    $(".mainList > a").click(function(){ // Attach click to <a> directly bellow .mainList
        $(this).next("ul").toggle();
    });
});

Hi thanks for your code. Yes, I realized eventually that I had to wrap everything within $(document).ready(function(){.
The way I have implemented it is this:

$(document).ready(function(){
        $("#navBox ul li.mainList").click(function(){           
            //$(this).find("ul").toggle();//this works but I want to do it with classes and make sure that there is only one nav item open
            $("ul.subList").removeClass("visible");
            $(this).find("ul").addClass("visible");

        });
    });

So the find() method finds nodes in the tree that are children and not siblings of the selector

You are welcome. But two concerns about your code:

1."#navBox ul li.mainList" will accept click in any content of 'mainList'. This means that when you click a item in the 'subList' the listener will be triggered too.
2."#navBox ul li.mainList" it's not a recommended selector. It works, but is not fast. Because jQuery will search all levels of itens to find it. In your case it's a lot better to use just 'li.mainList' or at least '#navBox > ul > li.mainList'.

Another thing, $(function(){}); it's an abreviation of $(document).ready(function(){});

With that in mind, I'd suggest:

$(function(){
    $("li.mainList > a").click(function(){           

        $("ul.subList").removeClass("visible");
        $(this).parent().find("ul").addClass("visible");

    });
});

Hiya, thanks for the explanation and for the amendments to my code. Point taken about the selector, it didn't occurr to me that I was selecting everything in subList, although I reckon the effects of such a selection might have been visible if I had something else - say another html element not relevant to the navigation - within mainList. Visually nothing happens if by clicking on a subList item I trigger the event listener, but I understand that it might have an inpact on the code speed?
thanks

You're welcome, and right.Even if doens't affect nothing at the current implementation, it will still be processed without changes to the UI.

If solved, please mark as such.

Seeya.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.