I have jQuery code that toggle class while I clicking on list element.
It's okay if you click on list area...
But when you click on span
element, which has text "Element1", it is not working.
ul
as a child (Element1).ul
elements.$(".sidebar>ul>li").has("ul").click(
function(e) {
if ((e.target == this)) {
$(this).children("ul").toggleClass("toggle");
}
}
);
.sidebar ul li ul {
display: none;
}
.sidebar ul li ul.toggle {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="sidebar">
<ul>
<li>
<span>Element1</span>
<ul>
<li>
<a>Subelement1</a>
</li>
</ul>
</li>
<li>
<span>Element2</span>
</li>
</ul>
</div>
Here's a way you can achieve this:
Please note that, as @ste2425 stated in his comment, "
according to the html5 spec li elements are only valid as a list item inside a ul or ol element.
" so you should consider wrapping the outerli
elements in anul
, orol
, tag.
var sidebarItems = $(".sidebar>li");
sidebarItems.on('click', function(e) {
var $th = $(this),
subList = $(this).children("ul");
// collapse other sub-ul by removing the class "open"
sidebarItems.not($(this)).children('ul').removeClass('open');
// check if the clicked element is a child of the a sub-ul which
// has class open, if NOT we toggle the "open" class, note that
// we use $(e.target) to convert the target into a jQuery object
if (!$(e.target).parents('ul').hasClass('open')) {
subList.toggleClass('open');
} else {
// just for demonstration purposes
console.log('you clicked ' + $(e.target).text());
}
});
li { cursor: pointer; font-weight:bold; }
li ul { display: none; }
li ul.open { display: block; }
li ul.open li{ font-weight:normal; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="sidebar">
<li>
<span>Element 1</span>
<ul>
<li><a>Sub element 1.1</a></li>
<li><a>Sub element 1.2</a></li>
</ul>
</li>
<li>
<span>Element 2</span>
<ul>
<li><a>Sub element 2.1</a></li>
<li><a>Sub element 2.2</a></li>
<li><a>Sub element 2.3</a></li>
</ul>
</li>
<li>
<span>Element 3</span>
<ul>
<li><a>Sub element 3.1</a></li>
<li><a>Sub element 3.2</a></li>
</ul>
</li>
</div>
Another way to do this is using CSS, instead of the span
elements we use "invisible" checkboxes with its label
elements. and we use this CSS to open the sub ul
which is a sibling of the relative checkbox:
li input[type="checkbox"]:checked ~ ul{ display: block; }
We still need JavaScript just in order to "uncheck" other checkboxes
var items = $('.sidebar input[type="checkbox"]');
items.on('click', function(){
items.not($(this)).prop('checked', false);
});
.sidebar li, li>label{ cursor: pointer; }
li>label{ font-weight:bold; }
.sidebar li ul{ display: none; }
.sidebar li input[type="checkbox"]{ display:none; }
.sidebar li input[type="checkbox"]:checked ~ ul{ display: block; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="sidebar">
<li>
<input id="item1" type="checkbox">
<label for="item1">Element 1</label>
<ul>
<li><a>Sub element 1.1</a></li>
<li><a>Sub element 1.2</a></li>
</ul>
</li>
<li>
<input id="item2" type="checkbox">
<label for="item2">Element 2</label>
<ul>
<li><a>Sub element 2.1</a></li>
<li><a>Sub element 2.2</a></li>
<li><a>Sub element 2.3</a></li>
</ul>
</li>
<li>
<input id="item3" type="checkbox">
<label for="item3">Element 3</label>
<ul>
<li><a>Sub element 3.1</a></li>
<li><a>Sub element 3.2</a></li>
</ul>
</li>
<li>
<input id="item4" type="checkbox">
<label for="item4">Element 4</label>
</li>
</div>