Reputation: 4344
I'm having trouble with jQuery selectors and I can't find the problem with my code.
I have a series of nested lists:
<ol id="chaps">
<li>Newton</li>
<ul class="assignments">
<li>One</li>
<li>Two</li>
</ul>
<li>Motion</li>
<ul class="assignments">
<li>One</li>
<li>Two</li>
</ul>
</ol>
The assignments
class has CSS set to display:none
to hide the list.
The jQuery I've tried is:
$("#chaps > li").click(function() {
$(this).closest("ul").find(".assignments").toggleClass("show");
});
...but it won't show the other options. I've gotten all of the .assignments
classes to show with a similar script, but I'd like to keep it to the immediate sibling. Any help with the selector would be appreciated.
Here's a CodePen Demo
Upvotes: 1
Views: 3995
Reputation: 397
Apart from getting your code to work, it is always recommended to have a valid markup. ul/ol can not be direct child of another ul/ol. Your html is not valid and has the following errors as per W3 validator:
1. Error: Element ul not allowed as child of element ol in this context. (Suppressing further errors from this subtree.)
From line 7, column 3; to line 7, column 26
on↩ ↩ < Contexts in which element ul may be used:Where flow content is expected.Content model for element ol:Zero or more li and script-supporting elements. 2. Error: Element ul not allowed as child of element ol in this context. (Suppressing further errors from this subtree.)
From line 12, column 3; to line 12, column 26
on↩ ↩ < Contexts in which element ul may be used:Where flow content is expected.Content model for element ol:Zero or more li and script-supporting elements.
Upvotes: 0
Reputation: 24638
ul
elements cannot be child elements of ol
elements but they can be child elements of li
elements. And, just so you know, for next time you need to use it, .closest( selector )
means:
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
$("#chaps > li").click(function() {
$(this).find("ul.assignments").toggleClass('hide');
});
.hide {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ol id="chaps">
<li>Newton
<ul class="assignments hide">
<li>One</li>
<li>Two</li>
</ul>
</li>
<li>Motion
<ul class="assignments hide">
<li>One</li>
<li>Two</li>
</ul>
</li>
</ol>
Upvotes: 4
Reputation: 11718
You can also make a more generic widget that doesn't rely on a given HTML structure...
$.fn.toggleMenu = function(opt){
opt = $.extend({
hideClass:"hidden",
selector:"ul",
triggerEvents:"click"
},opt)
function _init(){
$(this).each(_initEach);
}
function _initEach(){
$(this).on(opt.triggerEvents,toggleVis);
}
function toggleVis(e){
$(e.target)
.children(opt.selector)
.toggleClass(opt.hideClass);
}
_init();
}
$(".toggle_menu").toggleMenu({triggerEvents:"click mouseenter"});
This could be configured to accept any html structure.
Upvotes: 0
Reputation: 471
<li>Motion
<ul class="assignments">
<li>One</li>
<li>Two</li>
</ul>
</li>
This is the only way to nest list inside other list.
Upvotes: 2