views:

551

answers:

5

Been struggling with this simple selector problem a couple of hours now and must be missing something obvious. I have a <ul> in which some <li>s have nested <ul>s. Each <li> contains a link and when this is clicked I want to execute a function (rather than navigate), but importantly, this should only happen for the links contained in the parent <ul> and not any links that may be present in a nested <ul>. Simple you'd think:

HTML:

<ul>
 <li>
  <a href="dontleavethis.page">A link</a>
  <ul>
   <li><a href="navigate.there">A nested link</a></li>
   <li><a href="navigate.somewhere">Another nested link</a></li>
  </ul>
 </li>
</ul>

jQuery:

$('li:has(ul) a').click(function() { 
    bla bla bla...
    return false;
});

Thing is, no matter how I phrase my selector, I cannot stop the links in the nested <ul> from triggering the click handler. They clearly do not match the ":has(ul)" criteria of the selector but the handler still gets attached for some reason. What am I doing wrong here?

Many thanks in advance,

JS

+1  A: 
$('ul > li:has(ul) > a').click(function(){
    bla bla bla....
    return false;
});
idrumgood
Sorry, no dice. I get exactly the same behaviour from this. But thanks anyway!
John Schulze
Um, this is exactly the same thing as the answer you accepted... only it has the ul in there too (which won't change anything).
idrumgood
+5  A: 
$('li:has(ul) > a').click(...)

Your problem is that $('li:has(ul) a') means all a elements inside the li that has the ul, not only immediate children.

chaos
Ah, that makes perfect sense! Thanks!
John Schulze
A: 

If you give the top level links a class you can access them directly, without the need for any complex(ish) selector logic.

daddywoodland
this means that for every link a class is inserted, which clutters the html and generates unnessecary bandwidth. just giving the parent a class/id and selecting only direct ancestors is a lot more efficient
Litso
true but the other selectors being offered are reliant on the DOM structure remaining consistent, which can cause trouble moving forward. classes can also offer a descriptive selector, making the code more readable.
daddywoodland
A: 

You should give the main ul an id, I'll use "main" but you should try and think of a more descriptive one (for your own benefit). Then you can just use

$('ul#main > li > a').click(function() { 
    bla bla bla...
    return false;
});

The > will select only the direct ancestor of an element.

-edit- never mind, this also means the li's without an ul in it will have the style. @idrumgood's solution is best.

Litso
Yep, that will work of course. Was hoping there was a neat way to do it without having to assign an ID or class (the parent element of the list already has an ID).
John Schulze
A: 

could it be that the event is propagated?

how about

$('ul > li:has(ul) > a').click(function(event){
  bla bla bla....
  event.stopPropagation();
  return false;
});
gabtub