SwankyLegg
SwankyLegg

Reputation: 473

Selecting multiple li classes in a menu

I'm creating a portfolio site, and I'm struggling to select the proper elements with JQuery. My goal is to show/hide the .inner (Task) items when clicking the .outer (Category) items. I have .arrows that rotate when the menu is expanded.

This is a similar question, and the accompanying jsfiddle.

Thanks to Tats_innit for the original answer.

I have this HTML:

<li class="outer" hook="01">
    <div class="arrow"></div>
    Category 1
</li>
<li class="inner" id="menu-01">
    Task 1
</li>
<li class="inner" id="menu-01">
    Task 2
</li>
<li class="inner" id="menu-01">
    Task 3
</li>

<li class="outer" hook="02">
    <div class="arrow"></div>
    Category 2
</li>
<li class="inner" id="menu-02">
    Task 1
</li>
    <li class="inner" id="menu-02">
    Task 2
</li>
    <li class="inner" id="menu-02">
    Task 3
</li>

And this jquery:

$(document).ready(function(){
        $('.outer').click(function(){
            var elem = $('#menu-'+$(this).attr('hook')),
                arrow = $(this).children('.arrow')

            if (!elem.is(':visible'))  {
                arrow.rotate({animateTo:90, duration:128});
            } else {
                arrow.rotate({animateTo:0, duration:128});
            }
            elem.slideToggle('128ms', function() {
            });

        return false;
    });
});

I understand that I need to change var elem = $('#menu-'+$(this).attr('hook')) but I'm not sure how to display all instances of .inner. I didn't nest the .inner elements because I have a hover state background-color: #f1f1f1; for the .outer class.

Upvotes: 0

Views: 969

Answers (4)

Sunyatasattva
Sunyatasattva

Reputation: 5840

This problem can be solved, but there are many things wrong with your approach in the first place, so I would like to aim to change those, instead. And then solve the problem.

  1. The id attribute is unique. You cannot have multiple elements with the same id in the same page; for that reason, use class.
  2. hook is not a valid HTML attribute; while it is true that this won't hurt you and browsers will most likely ignore it, I would rather see it standardized as data-hook if you so wish. This will allow you also to use the standard APIs.
  3. You should nest the .inner inside the .outer because it makes sense semantically and it will degrade gracefully and be understandable to screen readers as well. The problem you mention about the background on hover, I think could be easily solved with some good CSS: though I didn't understand the specific issue, so I cannot say.

But fact is, that using nesting you probably don't need most of those ids, classes and random data attributes (unless obviously you need them for something else than just opening up a list).

After that you HTML will look like this:

<ul>
    <li class="outer">
         <div class="arrow"></div>
         Category 1
         <ul>
             <li>
                 Task 1
             </li>
             <li>
                 Task 2
             </li>
             <li>
                 Task 3
             </li>
         </ul>
    </li>
    <li class="outer">
         <div class="arrow"></div>
         Category 1
         <ul>
             <li>
                 Task 1
             </li>
             <li>
                 Task 2
             </li>
             <li>
                 Task 3
             </li>
         </ul>
    </li>
</ul>

And you jQuery like so:

$('.outer').click(function(){
    var elem  = $(this).children('ul'),
        arrow = $(this).children('.arrow')

    if (!elem.is(':visible'))  {
        arrow.rotate({animateTo:90, duration:128});
    } else {
        arrow.rotate({animateTo:0, duration:128});
    }
    elem.slideToggle('128ms', function() {
    });

    return false;
});

As a final note, .arrow is not a very semantic element, since it's not even used to activate the animation (the click is bound the the li.outer) I would remove it altogether and instead achieve the same effect using a pseudo-element on the said li, and perhaps rotate it with CSS3.

Edit

I am not sure why you were not able to make it function properly; though you tell me that you appreciated the comment regarding the nesting, your fiddle didn't use the correct nesting.

In any case, I put up an example for you with the advice I gave you here, and basically I just copied the code verbatim as I wrote it here. I made a few adjustments, though: such as implementing the CSS pseudoelement and getting rid of that div.arrow element, which honestly looked bad.

Obviously is just an example, but it shows how think this problem should be approached. Hopefully it will solve your doubts:

Working example

Upvotes: 4

Dr.Molle
Dr.Molle

Reputation: 117354

I guess you are looking for nextUntil()

$(this).nextUntil('.outer').slideToggle('218ms');

http://jsfiddle.net/bf7Ke/53/

Upvotes: 0

Ankit Agrawal
Ankit Agrawal

Reputation: 6124

<script>
$(document).ready(function(){
    $('li.inner').hide();
    $('.outer').click(function()
    {
        var elem = $(this).attr('hook');
        $('li.inner').hide();
        $(".menu-"+elem).toggle();
    });
});
</script>
<ul>
<li class="outer" hook="01">
<div class="arrow"></div>
Category 1
</li>
<li class="inner menu-01">
Task 1
</li>
<li class="inner menu-01">
Task 2
</li>
<li class="inner menu-01">
Task 3
</li>

<li class="outer" hook="02">
<div class="arrow"></div>
Category 2
</li>
<li class="inner menu-02">
Task 1
</li>
<li class="inner menu-02">
Task 2
</li>
<li class="inner menu-02">
Task 3
</li>
</ul>

first of all change li id to class because 2 li don't have same id

Upvotes: 1

jasonslyvia
jasonslyvia

Reputation: 2535

You can nest a set of outer and inner into a div

<div>
    <li class="outer">
        <div class="arrow"></div>
        Category 1
    </li>
    <li class="inner">
        Task 1
    </li>
    <li class="inner">
        Task 2
    </li>
    <li class="inner">
        Task 3
    </li>
</div>

then your js code goes like

$('.outer').click(function(){
    var elem = $(this).siblings('.inner'),
        arrow = $(this).children('.arrow')

    if (!elem.is(':visible'))  {
        arrow.rotate({animateTo:90, duration:128});
    } else {
        arrow.rotate({animateTo:0, duration:128});
    }
    elem.slideToggle('128ms', function() {
    });

    return false;
});

won't affect your background-color for outer class in the meantime

Upvotes: 1

Related Questions