tags:

views:

737

answers:

4

Hi, I need to apply a jQuery.click to the first level items only. How do I do that?

Here is my list:

<ul id="adminMenu">
  <li id="A">
    <h3><a href="">Item 1</a></h3>
  </li>
  <li id="B">
    <h3>Item 2</h3>
    <ul style="display: block;">
      <li id="a1"> Sub Item 1 </li>
      <li id="a2"> Sub Item 2 </li>
      <li id="a3"> Sub Item 3 </li>
    </ul>
  </li> 
  <li id="C">
    <h3>Item 3</h3>
    <ul style="display: none;">
      <li> Sub Item 4 </li>
      <li> Sub Item 5 </li>
    </ul>
  </li> 
</ul>

And here is the jQuery

jQuery('#adminMenu > li').click(function(){
  alert('test');
});

UPDATE
The Alert should not fire when I click a Sub Menu item, only when I click list item A, B or C.

SOLUTION 1
This is working code based on Marcels suggestion.

  jQuery('#adminMenu > li > h3').click(function(e) {
    var activeUL = jQuery("#adminMenu > li ul:visible");
    var activeLI = jQuery("#adminMenu > li ul:visible").parent('li:first');
    var clicked = jQuery(this).parent('li:first');
    // Close submenu
    activeUL.hide('fast');
    // Open submenu
    if( activeLI.attr('id') != clicked.attr('id') )        
      clicked.children('ul').show('fast');
  });

SOLUTION 2
This is working code based on Eyelids suggestion.

  jQuery('#adminMenu > li').click(function(e) {
      var clicked = jQuery(e.target);
      // Ensure we're checking which list item is clicked,
      // other children should be allowed
      if(!clicked.is('li') && clicked.parents('li').length > 0) {
          // :first ensures we do not select higher level list items
          clicked = clicked.parents('li:first');
      }
      // If clicked list item is a child of another list item, we'll exit here
      if(!clicked.is('#adminMenu > li')) {
          return;
      }
    var activeUL = jQuery("#adminMenu > li ul:visible");
    var activeLI = jQuery("#adminMenu > li ul:visible").parent('li:first');

    // Close submenu
    activeUL.hide('fast');
    // Open submenu
    if( activeLI.attr('id') != clicked.attr('id') )        
      clicked.children('ul').show('fast');
  });

Thanks guys! I would never have managed this without your help! :)

A: 

jQuery('#adminMenu li:first')

McLovin
If I'm not wrong, that will only apply the .click to the first li item. I need to apply it to ALL first level li items.
Steven
-1 This will select the first matching li element. That is not the same as selecting all the first-level li elements.
Ken Browning
+3  A: 
jQuery('#adminMenu > li').click(function(e) {
    var clicked = jQuery(e.target);
    // Ensure we're checking which list item is clicked,
    // other children should be allowed
    if(!clicked.is('li') && clicked.parents('li').length > 0) {
        // :first ensures we do not select higher level list items
        clicked = clicked.parents('li:first');
    }
    // If clicked list item is a child of another list item, we'll exit here
    if(!clicked.is('#adminMenu > li')) {
        return;
    }
    alert('test');
});

Updated to exit if clicked list item is not an immediate descendant of #adminMenu.

eyelidlessness
That was only mistyping in here. I've updated the code now.
Steven
The above code, will also fire the alert when i click a sub item.
Steven
If the code you have is still not working how you want, can you clarify the question? Do you want the event handler to ignore clicks on child list items?
eyelidlessness
Gotcha. Editing now...
eyelidlessness
yes. Clicking Sub Item 1 should NOT fire the Alert.
Steven
Thanks eyelidlessness. I'm using your solution considering your comment to Marcel.
Steven
My activeUL and activeLI restricts this to only 1 level. Is there a more general way to do it?
Steven
+3  A: 

The issue is, that you add the click to the whole LI (which includes all childs etc). You have to "clickify" the labels only, so use:

jQuery("#adminMenu > li > h3").click(...);
Marcel J.
It's the first one. But it gets applied to my sub elements. So clicking Sub Item 1 also fires the Alert.
Steven
Yea, took me some time to grasp the issue ;) Try the new one.
Marcel J.
+1 You beat me to it. Upvoted for using less code.
MikeWyatt
MikeWyatt, it's only less code assuming that the structure used is the only way it'll ever be used. Add any other child elements or even child text nodes to the top-level list items, and you'll get undesired behavior.
eyelidlessness
And I want to emphasize that there is no way to ensure that text nodes which are immediate children of the top-level list items are clickable with only a selector in jQuery. Much as I'd like jQuery/Sizzle to allow selecting non-element nodes, it doesn't.
eyelidlessness
Thanks Marcel. I got a working solution now with your example. No I'll dive into Eyelids suggestion, as it is a slightly better solution :)
Steven
A: 

Get a set of elements containing all of the unique immediate children of each of the matched set of elements.

children( [expr] )

http://docs.jquery.com/Traversing/children

   jQuery('#adminMenu').children('li').children('h3').click(function()
   {  
       alert('test');
   });
Mark Schultheiss
Nope. That will also fire the Alert when i click Sub Item 1.
Steven
Edited after clarification of question (I might have been a bad reader :)
Mark Schultheiss
The difference is that ("#adminMenu > li > h3") should match "all sub elements, not just immediate children, so you should have no clicks on "h3" get fired on sub elements of "h3' if I did this right. (making assumption you "might" have an "h3" inside the inner li as well)
Mark Schultheiss