How to Get Anything You Want - part 2


A couple weeks ago I wrote about traversing the DOM with jQuery’s selector expressions to get any elements in the document (see How to Get Anything You Want - part 1). This time around, I’m going to focus on jQuery methods that provide even more ways to get elements. Some of these methods have a nearly identical counterpart among the selector expressions, but for the most part, the two ways of getting elements complement each other.

Once again, I’ve put together a short paragraph and an ordered list scattered with inline elements such as <em>, <code>, and links. This time it’s wrapped in a DIV with an ID of “jqdt2,” which allows me to focus the demonstration to one area of this page.

Each button below the "jqdt2" DIV will toggle a background color on and off for the parts of the DIV described.

This is a paragraph of text with class=”goofy.” It has an external link, some $(code), and a same-page link.

  1. list item 1 with dummy link to silly.pdf
  2. list item 2 with class=”goofy
  3. list item 3 with class=”funny”
  4. list item 4 with silly link to silly.pdf
  5. list item 5 with class=”goofy

Click a link to toggle the selector’s highlighting

  • get the first list item within the element with an id of “jqdt2.”
    $('#jqdt2').find('li').eq(0)
  • get the first 3 list items. “lt” stands for “less than,” and it starts counting at 0, not 1.
    $('#jqdt2').find('li').lt(3)
    $('#jqdt2').find('li').slice(0,3)
  • get list items 1, 2, 4, and 5 because they’re the siblings of “funny.” $('#jqdt2').find('li.funny').siblings()
  • get all list items that contain the string “silly” as long as they are not greater than the third list item. So, even though list item 4 has the word “silly” in it, it won’t be selected because it is greater than the third.
    $('#jqdt2').find('li').not(':gt(2)').contains('silly')
    $('#jqdt2').find('li').not(':gt(2)').filter(':contains(silly)')
  • first get all list items inside “jqdt2″ and then filter them so that it ultimately only gets the list items that have a class of “goofy.”
    $('#jqdt2').find('li').filter('[@class=goofy]')
    $('#jqdt2').find('li').filter('[class=goofy]')
    or, better yet: $('#jqdt2').find('li.goofy')
  • $('#jqdt2')
        .find('li.funny')
          .css('backgroundColor','#0ff')
        .end()
        .find('p > strong')
          .css('backgroundColor','#ff0')

    With this example you can see that jQuery’s chaining does not have to occur on a single line, but can be extended to multiple lines for better readability. I’ve also exposed the CSS backgroundColor setting that occurs in all of these examples so that you can see how .end() works. Any time you use one of jQuery’s DOM traversing methods, you can back out of it after you have done what you want with it. Here, the first .find() applies CSS to list items with a class of “funny”; the .end() backs us out of that set of jQuery objects and up to the opening $('#jqdt2'); the final .find() method gets a completely separate group of DOM nodes and applies an aqua background color to it. Also, note that I use the DOM property “backgroundColor” rather than the CSS property “background-color.” While either one should work with jQuery, CSS properties that contain a hyphen will break in some builds. Therefore, I recommend “camel-casing” those properties, just to be safe.

  • $('li.goofy')
    .parents(’#jqdt2′)
    .children(’p')
    .next()
    .find(’a')
    .parent()

    This final example is a ridiculously circuitous traversal sequence that probably isn’t practical in itself, but I wanted to show a couple more of the methods at your disposal. Unlike all the other examples, this one doesn’t start by narrowing the possible DOM elements to those within an element with an id of “jqdt2.” Instead, it starts with all list items with a class of goofy, and then gets any ancestor with an id of “jqdt2″ (since IDs should be unique, there should be only one). Next, it gets all children of “jqdt2″ that are paragraphs and moves on to the next sibling, which in this case is the ordered list (<ol>). Finally, it looks for links within that ordered list and gets the parent of each. So, by the end of all this skipping around the DOM, we should have selected list items 1 and 4.

For a complete list of DOM traversal methods, visit VisualjQuery.com and click on “DOM” and then “Traversing.” In addition to the ones covered in this entry, you’ll find the following:

  • .is()
  • .prev(): just like next(), but in the opposite direction
  • .parents(): functions the same as .ancestors() As of jQuery 1.1, .ancestors() is no longer supported. Please use .parents() instead.
  • .add(): allows you to add another group of jQuery objects

21 Responses to “How to Get Anything You Want - part 2”

  1. krdr Says:

    We want more! We want more!

  2. Chris Ovenden Says:

    Awesome! Thanks.

    Hey, wait… I’m out of a job! Anyone can do DOM scripting now. Damn you. Damn you to hell.

  3. Karl Says:

    krdr: I’m working on it. ;)

    Chris: You are hilarious! Glad you like the entry. And don’t worry — if client-side scripting follows the pattern of desktop publishing, there will always be a need for people who really know what they are doing.

  4. Dylan Says:

    Thanks for the work. I just started looking in to jQuery seriously after using YUI and YUI-ext a little bit. I’m an ASP.NET platform guy, so making the transition to DOM scripting and being unobtrusive in general is a bit of a head-scratcher. However, with resources like this it’s coming along. Now if I can just figure out when to use $(this) and when to use this my life will be a lot easier–kind of odd in JS where function can be a method, a class, a function, a…. ;-)

    Oh, and if you’re looking for another great article to write (that I will wholesale borrow from), how about How to write a jQuery extension to add a toggle selection to group. Jack Slocum has made a nice Element.radioClass() method that I’ve kind of hacked in jQuery for toggling the active tool in a toolbar, but how to make that in to a generic plugin? There’s the rub(ber ducky).

    Anyway, thanks for saving me approximately 5 hours of my life.

  5. agencia de web Says:

    Congratulations for your work. Its realy a good job.
    And thanks for shared….. ;-)

    kakaroto

  6. willi Says:

    Hallo,

    realy good. helped me diving into jQuery.
    if you can do such a thing for html tables with indirect references, this would be realy cool.
    selection all the rows there the cell of the column that corresponds to the column where the header contains ‘Sun’ gets emphasized.
    and this also for columns.

    Thx, Willi

  7. Ronald Allan Says:

    ei thanks! i will try this code.. actually i need this kind of code for my new project.

    im using jquery for a month now and its cool!!

    thanks again!

  8. jQuery Tips » Selectors ในแบบฉบับของ jQuery Says:

    […] to get everything you want part 1 How to get everything you want part 2 jQuery […]

  9. Adrian Jacob Says:

    Hi Karl, another great post.

    Im a complete newbie to jQuery and have one little issue that I hope you can help me with (dont scoff :p)

    I want to add nice jquery effects to some xhtml navigation so the sub menu will fade in. The basic xhtml will be similar to that below:

    <div id=”nav”>
    <ul>
    <li><a href=”#”>dfgdfg</a></li>
    <li><a href=”#”>dfgdfg</a>
    <ul>
    <li><a href=”#”>dfgdfg</a></li>
    <li><a href=”#”>dfgdfg</a></li>
    </ul>
    </li>
    <li><a href=”#”>dfgdfg</a></li>
    <li><a href=”#”>dfgdfg</a>
    <ul>
    <li><a href=”#”>dfgdfg</a></li>
    <li><a href=”#”>dfgdfg</a></li>
    </ul>
    </li>
    </ul>
    </div>

    The key is i cant have any class or id on any ul/li as its all cms driven, the surrounding div ID should allow for the code focus.

    I got as far as this with the JQuery side of things:

    $(document).ready(
    function(){
    $(”li”).hover(function(){
    $(’li’).children(’ul’).fadeIn();
    },function(){
    $(’li’).children(’ul’).fadeOut();
    });
    }
    );

    But this obviosuly doesnt do the trick. It shows both submenus on any li.

    What am I doing wrong?

  10. Karl Says:

    Hi Adrian,

    Instead of $('li').children('ul'), try $(this).children('ul').

  11. Adrian Jacob Says:

    Excellent :) Works a dream….

    Much appreciated Karl, keep up the good work….

  12. frances Says:

    Thanks for a great site, Karl! I’m just getting into jQuery and I couldn’t do it without your tutorials. I think I have the same question as willi above. I’m trying to highlight each column in a table when someone hovers over one of the elements. I’ve added classes to each of the related ths and tds, and I can get it to work but only if I define the class absolutely, like this:

    
    var $classWord = "dayTue";
    
    var $currentClass = "." + $classWord;
    
    var $selectClass = $("table#eventsWeek").find($currentClass);
    
    $($selectClass).hover(
     	function(){
     		$($selectClass).addClass("on");
     	},
    	function(){
    		$($selectClass).removeClass("on");
    	}
     );
    

    (The highlight is done with the css class “on”.) What I need is for it to change as the mouse moves… I can’t figure out how to create a variable to hold the class of the element being hovered over, which would then be used to select the other elements with the same class, which I think would be something like this:

    
    var $classWord = ($(this).mouseover(
    	function() {
    		$(this).attr("class");
    	}
    ));
    
    var $currentClass = "." + $classWord;
    
    var $selectClass = $("table#eventsWeek").find($currentClass);
    
    $($selectClass).hover(
     	function(){
     		$($selectClass).addClass("on");
     	},
    	function(){
    		$($selectClass).removeClass("on");
    	}
     );
    

    I guess that’s the heart of my question: How can you select an attribute of the current element being clicked or hovered over?

    thanks for the help and keep up the great work!
    -frances

  13. Karl Says:

    Hi Frances,

    I think I know what you’re getting at. I think the secret is to make use of the this keyword. Something like this:

    $('td').hover(function() {
      $('td.' + this.className).addClass('on');
    }, function() {
      $('td').removeClass('on');
    });
  14. frances Says:

    Awesome! It’s so simple and yet I was tying myself in knots trying to figure it out. I think I still have to get the hang of jQuery’s chaining… Thanks so much for the help and a great example to learn from!

  15. Andy Says:

    This is great article, thanks, Karl!
    I`m newbie in JQuery and ask you to help.
    I have this code:

    
    #left
      ul
        li
          ul ----------- how to get it?
            ...
              a class="active"
            ...
          ul
          ul
    

    The question: how to get #left ul li ul which have inside<a class="active">.
    The problem (for me): tag a is on unknown level inside ul

  16. Andy Says:

    For previous post:

    
    $('#left ul li ul:has(.active_page)')
    

    Is this correct?

  17. Karl Says:

    Hi Andy,

    Well, if the class is “active”, then you’ll need to have …:has(.active), but other than that, it looks fine. You probably don’t need the first ul, unless you have to distinguish it from an ol. So, all together, it might look like this:
    $('#left li ul:has(.active)')

  18. Sean Says:

    Thanks a ton for the tutorial! I was able to solve a problem with a selector that was below the hovered item like:

    $(".outerDiv").hover(
      $(this).find('.innerDiv').show(),
      $(this).find('.innerDiv').hide(),
    );

    This worked incredibly easily to show a div when you hovered. Basically, it shows an edit link when you hover, and hides it when you lose hover.

    Thanks again for a great site!

  19. Sean Says:

    Oops … errant comma. Fix below:

    $(".outerDiv").hover(
      $(this).find('.innerDiv').show(),
      $(this).find('.innerDiv').hide()
    );
  20. Sean Says:

    Please don’t tell my friends I’m an idiot:

    $(".outerDiv").hover(
    	function(){ $(this).find(".innerDiv").show(); },
    	function(){ $(this).find(".innerDiv").hide(); }
    );
  21. Paul Says:

    Please don’t tell my friends I’m an idiot

    If they are true friends they will already know :)

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <pre> <em> <i> <li> <ol> <strike> <strong> <ul>

IMPORTANT: If you wish to post code examples, please wrap them in <code> tags. Multi-line code should be wrapped in <pre><code> </code></pre> Also, use &lt; instead of < and &gt; instead of > in the examples themselves. Otherwise, you could lose part of the comment when it's submitted.