Reputation: 9105
Consider this simple html list :
<ul>
<li><a href="http://google.com/">Test</a></li>
<li><a href="http://google.com/">Test2</a>
<ul>
<li><a href="http://google.com">Test2 - 1</a></li>
<li><a href="#3">Test2 - 2</a></li>
</ul>
</li>
</ul>
Now this 3 jQuery lines which makes it collapsible :
$('ul > li').on('click', function(e) {
e.preventDefault();
$(this).find('ul').slideToggle();
});
The matter here is that if a link has been clicked in the deeper ul
I wanted it to follow the link, which in jQuery will be :
if(this.nodeName != 'A') {
e.preventDefault();
}
At the moment the nodeName
is LI
and isn't the last clicked child element.
Question : Is it possible to do this without having a second event handler for deeper elements ? (i.e : $('ul > li ul li a').click()
)
I tried e.stopPropagation
and a lots of other css selectors
(ul > *
, ul li
etc.) without success.
Upvotes: 0
Views: 209
Reputation: 1831
Try this:
$('li > ul').prev().on('click', function(e) {
e.preventDefault();
$(this).next().slideToggle();
});
And here the link to the jsfiddle.Here the li > ul
selector find each ul
child of li
then .prev()
selects the previosu sibling (i.e. the a
tag). This way we can prevent the default behaviour of a
tag (i.e. following the link) and slideToggle the next (i.e. the ul
)
Upvotes: 1
Reputation: 9105
After some researches I came to this answer :
$('ul > li').on('click', function(e) {
e.stopPropagation();
if(!$(this).find('ul').length == 0) {
e.preventDefault();
$(this).find('ul').slideToggle();
}
});
So it'll follow links if no ul
element is founded in the clicked element. If you've got a better solution please share :).
This solution won't work with a specified ul
by ID
:
$('ul#test > li').on('click', function(e) {
e.stopPropagation();
if(!$(this).find('ul').length == 0) {
e.preventDefault();
$(this).find('ul').slideToggle();
}
});
See updated fiddle here, can somebody explain why ?
Ok thanks to Simon
I've corrected with my listener on the li
from the ul#test
:
$('ul#test').on('click', 'li', function(e) {
e.stopPropagation();
if(!$(this).find('ul').length == 0) {
e.preventDefault();
$(this).find('ul').slideToggle();
}
});
Wonderful !
Upvotes: 0
Reputation: 66663
Since your root selector is 'ul > li'
it will match nothing but LIs. i.e. There is no way you'll be matching clicks to other elements inside a handler bound using that selector.
What you can do instead is a more generic selector and filter inside the handler:
For example:
$('ul *').on('click', function(e) {
// leaf LIs only
if($(this).is('li') && $(this).children().length == 0) {
e.preventDefault();
$(this).find('ul').slideToggle();
}
});
OR, You can combine the selectors and handle it using one handler like:
$('ul > li, ul > li ul li a').on('click', function(e) {
if($(this).is('a')) return true; // follow links
e.stopPropagation();
$(this).find('ul').slideToggle();
}
Upvotes: 0