How to Get Anything You Want – part 2

read 39 comments

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
comment feed

39 comments

  1. krdr

    We want more! We want more!

  2. Awesome! Thanks.

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

  3. 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

    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. Congratulations for your work. Its realy a good job.
    And thanks for shared….. ;-)

    kakaroto

  6. willi

    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. 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. Adrian Jacob

    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?

  9. Hi Adrian,

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

  10. Adrian Jacob

    Excellent :) Works a dream….

    Much appreciated Karl, keep up the good work….

  11. frances

    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

  12. 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');
    });
  13. frances

    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!

  14. Andy

    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

  15. Andy

    For previous post:

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

    Is this correct?

  16. 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)')

  17. 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!

  18. Oops … errant comma. Fix below:

    $(".outerDiv").hover(
      $(this).find('.innerDiv').show(),
      $(this).find('.innerDiv').hide()
    );
  19. Please don’t tell my friends I’m an idiot:

    $(".outerDiv").hover(
    	function(){ $(this).find(".innerDiv").show(); },
    	function(){ $(this).find(".innerDiv").hide(); }
    );
  20. Please don’t tell my friends I’m an idiot

    If they are true friends they will already know :)

  21. Samy

    hi karl,

    i’m trying to use the following code and what i want is to hide a div “.nextblock” when i click any where on the page, except on that div. But this is not working. It hides the block even if i click on the block.

    $(“body,.div”).not(“.nextBlock”).click(function () {

    $(“.nextBlock”).hide();

    });

    This one works when i use a image instead of a div or a table in the filter.

    $(“body,.img”).not(“.testImg”).click(function () {

    $(“.nextBlock”).hide();

    }); // this works

    can you please tell me why the first one is not working and a better way to implement it.

    Thanks!

  22. Frank

    Hi,

    thanks for the work – but in my opinion the way it is presented lacks any senseful
    structure.

    Which included js- and css-files are needed for the examples, which are for the rest of the page?

    Everything is so mangled into anything else – i tried to get my hands on the relevant parts just dealing with the examples – sysiphos like work – so i dropped it.

    I don’t think the examples are of any help when presented like this.

  23. Frank

    Sorry, one more,

    it is even no longer obvious which of the included js-files is the original jquery-js-file.
    Why call it “somehow” if it has a name: “jquery”?
    Has it been altered to achieve the results of the examples?
    Do i need ‘a’ or maybe rather ‘a.js’ to reproduce the examples?

    Helplessly stuck

  24. Frank

    Up to now
    i found out that the really needed files for the examples to work are:

    - syntax_hilite_css.css
    - sytax_hilite_js.js
    - dom-traverse1.js
    - a.css
    - a.js

    It seems that a.js is an excerpt of the jquery.js, or maybe the jquery.js is not used at all here
    and a.js is, well, what is it?

    Which file does what?

    Why do you give beginners such a hard time getting a grip on how it works “as a whole”?

  25. Frank

    I got the point.

    This is not meant to be a working (standalone) example for highlighting specific parts of a web page – it is examples for how to reach/select elements.

    So my comments are not too much on topic, sorry for that.

    Still i think separating example code (and the included files needed just for the examples) from the rest of the page is a good idea.

  26. Hi Frank,
    Thanks for the feedback. I can see how it could have been confusing for you if you were looking for a packaged solution to a particular problem. You’re right in your last comment, though, that this post is more of an exercise rather than a standalone example. Think of it more as training drills than as a game. Still, I appreciate where you’re coming from and will consider how to make this sort of thing clearer in future posts. Thanks.

  27. is it possible to get the id’s of all the children of an element and throw it into an array, or use it in a loop?
    I am dynamically adding ‘a’ tags with unique id’s inside a div, and for each a tag I want to init a plugin like lightbox. I hope this makes sense…

    • Sure, you could do something like this:

      var childIds = [];
      $('#mydiv').children().each(function() {
        childIds.push(this.id);
      });
      

      Or, you could use the .map() method:

      var childIds = $('#mydiv').children().map(function() {
        return this.id;
      }).get();
      
  28. Karl,
    I see you have been such a big help to everyone here! Thank you for that!

    I have a small issue I’m trying to figure out. I apologize for the length of this comment in advance.
    I want to add a class to the first 3 ‘p’ in my divs on a page. And there are never the same amount of “p”s in the divs.
    The HTML looks something like this.

    <div class=”myclass”>
    <p></p>
    <p></p>
    </div>
    <div class=”myclass”>
    <p></p>
    <p></p>
    <p></p>
    </div>
    <div class=”myclass”>
    <p></p>
    <p></p>
    <p></p>
    <p></p>
    </div>…

    jquery I have so far is…
    $('.naetext').children('p:lt(3)').addClass('newclass');

    What this does is it adds a class of “newclass” to the first 3 “p”s consecutively and not the first 3 of each “set” of “p”s
    So my HTML looks like this

    <div class=”myclass”>
    <p class=”newclass”></p> added class 1
    <p class=”newclass”></p> added class 2
    </div>
    <div class=”myclass”>
    <p class=”newclass”></p> added class 3
    <p></p>
    <p></p>
    </div>
    <div class=”myclass”>
    <p></p>
    <p></p>
    <p></p>
    <p></p>
    </div>

    What I need is this…
    <div class=”myclass”>
    <p class=”newclass”></p> added class 1
    <p class=”newclass”></p> added class 2
    </div>
    <div class=”myclass”>
    <p class=”newclass”></p> added class 1
    <p class=”newclass”></p> added class 2
    <p class=”newclass”></p> added class 3
    </div>
    <div class=”myclass”>
    <p class=”newclass”></p> added class 1
    <p class=”newclass”></p> added class 2
    <p class=”newclass”></p> added class 3
    <p></p>
    </div>

    Man, I hope that makes sense. I appreciate your time!

  29. I’m sorry, my jquery actually is this:
    $('.myclass').children('p:lt(3)').addClass('newclass');

  30. sayed khalid sultani

    hi how can we check for td with 2 classes with different class name in single tr ,thanks
    $('#table1 tr .abc )

  31. nelson

    hi,
    how can i make the selectors case sensitive?
    is there any smart way?
    example: remove all SPAN elements with the same background-color

    _ lower_
    _upper_
    _both_

    $("span[style*='color']").remove();
    $("span[style*='aaccee']").remove();

    thanks for all the tipps and tutorials,
    nelson

  32. Finally I learned how end() works!!!, thanks so much.

4 Pings

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

  2. [...] For more reading, How to Get Anything You Want – part 2 [...]

  3. [...] For more reading on this topic, How to Get Anything You Want – part 2 [...]

Sorry, but comments for this entry are now closed.