Reputation: 473
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 .arrow
s 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
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.
id
attribute is unique. You cannot have multiple elements with the same id
in the same page; for that reason, use class
.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..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.
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:
Upvotes: 4
Reputation: 117354
I guess you are looking for nextUntil()
$(this).nextUntil('.outer').slideToggle('218ms');
Upvotes: 0
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
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