Selecting: The Core of jQuery

Time is ticking, and deadlines wait for no one. The client has noted that people have been quoting incorrect celebrity IDs from the web site. This is because the celebrities’ names are all laid out in one big table and it’s difficult for users to line up a celebrity with the correct reference ID. Our client tells us that he wants every other row to be a light gray color so the users can easily find their favorite celebrity.

We have jQuery ready to do our bidding—it just needs us to choose a target for it. Selecting the elements you want to modify on the page is really the art of jQuery. One of the biggest differences between being a novice and ninja is the amount of time it takes you to grab the elements you want to play with!

Simple Selecting

Our task is to select alternate table rows on the celebrity table. How do we do this? When selecting with jQuery, your goal should be to be only as specific as required: you want to find out the most concise selector that returns exactly what you want to change. Let’s start by taking a look at the markup of the Celebrities table, shown below:

celebrities table

We could start by selecting every table row element on the entire page. To select by element type, you simply pass the element’s HTML name as a string parameter to the $ function. To select all table row elements (which are marked up with the <tr> tag), you would simply write:

$('tr')

Nothing Happens!

If you run this command, nothing will happen on the page. This is expected—after all, we’re just selecting elements. But there’s no need to worry; soon enough we’ll be modifying our selections in all sorts of weird and wonderful ways.

Similarly, if we wanted to select every paragraph, div element, h1 heading, or input box on the page, we would use these selectors accordingly:

$('p')

$('div')

$('h1')

$('input')

But we don’t want to change every table row on the celebrity page: just the rows in the table that have the celebrity data. We need to be a bit more specific, and select first the containing element that holds the list of celebrities. If you have a look at the HTML and at the image of the Celebrities table, you can see that the div that contains our celebrity table has an id of celebs, while the table itself has a class of data. We could use either of these to select the table.

jQuery borrows the conventions from CSS for referring to id and class names. To select by id, use the hash symbol (#) followed by the element’s id, and pass this as a string to the jQuery function:

$('#celebs')

You should note that the string we pass to the jQuery function is exactly the same format as a CSS id selector. Because ids should be unique, we expect this to only return one element. jQuery now holds a reference to this element.

Similarly, we can use a CSS class selector to select by class. We pass a string consisting of a period (.) followed by the element’s class name to the jQuery function:

$('.data')

Both of these statements will select the table but a class can be shared by multiple elements—and jQuery will happily select as many elements as we point it to. If there were multiple tables (or any other elements for that matter) that also had the class data, they’d all be selected. For that reason, we’ll stick to using the id for this one!

Can You Be More Specific?

Just like with CSS, we can select either $('.data') or the more specific $('table.data'). By specifying an element type in addition to the class, the selector will only return table elements with the class data—rather than all elements with the class data. Also, like CSS, you can add parent container selectors to narrow your selection even further.

Narrowing Down Our Selection

We’ve selected the table successfully, though the table itself is of no interest to us—we want every other row inside it. We’ve selected the containing element, and from that containing element we want to pick out all the descendants that are table rows: that is, we want to specify all table rows inside the containing table. To do this, we put a space between the ancestor and the descendant:

$('#celebs tr')

You can use this construct to drill down to the elements that you’re looking for, but for clarity’s sake try to keep your selectors as succinct as possible.

Let’s take this idea a step further. Say we wanted to select all span elements inside of p elements, which are themselves inside div elements—but only if those divs happen to have a class of fancy. We would use the selector:

$('div.fancy p span')

If you can follow this, you’re ready to select just about anything!

Testing Our Selection

Right, back to our task at hand. It feels like we’re getting closer, but so far we’ve just been selecting blindly with no way of knowing if we’re on the right path. We need a way of confirming that we’re selecting the correct elements. A simple way to achieve this is to take advantage of the length property. length returns the number of elements currently matched by the selector. We can combine this with the good ol’ trusty alert statement to ensure that our elements have been selected:

$(document).ready(function() {
  alert($('#celebs tr').length + ' elements!');
});

This will alert the length of the selection—7 elements—for the celebrity table. This result might be different from what you’d expect, as there are only six celebrities in the table! If you have a look at the HTML, you’ll see where our problem lies: the table header is also a tr, so there are seven rows in total. A quick fix involves narrowing down our selector to find only table rows that lie inside the tbody element:

$(document).ready(function() {
  alert($('#celebs tbody tr').length + ' elements!');
});

This will alert the correct length of 6 elements—the jQuery object is now holding our six celebrity table row elements.

If the alert shows 0, you’ll know there’s a mistake in your selector. A good way to troubleshoot this sort of issue is to reduce your selector to the smallest, simplest one possible.

In our example, we could simply write $('#celebs'), which would select just the div element and alert a length of 1. From here you can make your selectors more specific, and check that you’re selecting the correct number of elements as you go.

Filters

With the knowledge that we’ve successfully selected all of the table rows, narrowing our selection down to every other row is simple—because jQuery has a filter to do it. A filter removes certain items, and keeps only the ones we want. You’ll acquire a feel for what can be filtered as we work through some more examples, but for now we’ll just jump straight to the filter we need for our zebra stripes:

$(document).ready(function() {
  alert($('#celebs tbody tr:even').length + ' elements!');
});

Filters are attached to the item you want to filter (in this case, the table rows) and are defined by a colon, followed by the filter name. The :even filter used here keeps every even-indexed element in the selection and removes the rest, which is what we want. When we alert the selection length now, we see 3, as expected. All of our odd-numbered rows have been filtered out of the selection. There is a wide array of jQuery selector filters available to us: :odd (as you might expect), :first, :last, :eq() (for selecting, for example, the third element), and more. We’ll look at each of these in more detail as we need them.

Selecting Multiple Elements

One last trick for basic selecting is the ability to select multiple elements in a single statement. This is very useful, as we’ll often want to apply the same action to several elements in unrelated parts of the page. Separating the selector strings with commas allows you to do this. For example, if we wanted to select every paragraph, div element, h1 heading, and input box on the page, we’d use this selector:

$('p,div,h1,input')

Learning how to use all these different selectors together to access exactly the page elements you want is a big part of mastering jQuery. It’s also one of the most satisfying parts of using jQuery, since you can pack some fairly complex selection logic into a single short line of code!

Becoming a Good Selector

Selecting may seem quite easy and, up to a point, it is. But what we’ve covered so far has only just scratched the surface of selecting. In most cases the basics are all you’ll need: if you’re simply trying to target an element or a bunch of related elements, the element name, id, and class are the most efficient and easiest ways to achieve this.

When moving around the DOM from a given element, the situation becomes a little trickier. jQuery provides a myriad of selectors and actions for traversing the DOM. Traversing means traveling up and down the page hierarchy, through parent and child elements. You can add and remove elements as you go, applying different actions at each step—which lets you perform some mind-bogglingly complex actions in a single jQuery statement!

If you’re a wiz at CSS, you’ll already be familiar with a lot of the statements; they’re mostly borrowed directly from the CSS specification. But there are probably a few that you’re unfamiliar with, especially if you’ve yet to spend much time learning CSS3 selectors. Of course, we’ll be covering and learning advanced selection techniques as we implement them in our examples and demos. For this reason, any time you want to find out more about all the jQuery selectors available, you can just head over to the online documentation and browse away!

note:Want more?

Check out the book and buy it online at jQuery: Novice to Ninja, by Earle Castledine & Craig Sharkie

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • deathshadow

    Hey look, another example of using that fat bloated scripting for nothing garbage to do CSS’ job.

    Old school just add class=”even” every other TR.. or with CSS3 it’s called nth-child.

    Either way is better than relying on some trash scripting that an increasing number of Internet users won’t even see.

    I’d punch myself in the face before wasting javascript on something like that.

    • kaf

      deathshadow your dislike of jquery is utterly baffling to me. Its a great tool that speeds up development immensely and actually makes javascript usable.

      However I totally agree with you here. This should be done by putting alternate classes on your rows on the server side and applying a little css. Sometimes when someone first discovers javascript (or jQuery) they go a little mad with power and start to use it everywhere.
      “If your only tool is a hammer every problem starts to look like a nail”

      Btw “an increasing number of Internet users won’t even see” doesn’t make sense. Javascript is more available now than it ever has been. ?!

      • deathshadow

        It’s also increasingly blocked or enabled selectively — See the 83 million noscript plugin for FF downloads, Opera’s per site settings, selective script blocking the latest versions of mcAfee and Nortons are putting on machines (fun explaining that one to facebook users)…

        As to my dislike being ‘baffling’ — it’s like my dislike of C. I can work with it if I have to; but many times I’d prefer to be working in ASM because even that is less cryptic…

        You kind-of hit my dislike for it on the head with the ‘only tool is a hammer’ part — it seems like many times people start using it for EVERYTHING, for no good reason.

        99% of the stuff I’ve seen done in jquery is either stuff that could be better handled by CSS or proper markup, stuff that is smaller and simpler to code WITHOUT it, or just plain “gee ain’t it neat” animooted garbage that as a user I don’t even want to see on websites in the first place; much less as a developer.

        Especially with the number of people who don’t even take graceful degredation into consideration on the simplest of things.

    • Gabe

      Even tho I agree with your comment about how this particular job should be done, I’m inclined to think that you’re totally uneducated when it comes to jQuery and jQuery UI and that you probably never have used it, just skimmed trough it and taken a look at the size of .js file and made your decision about it. If you can’t provide alternative(s) or back your opinion up, why even comment?

      • deathshadow

        Darned straight I take a look at the size and forget about it — since my normal target for a single page is 70k and my limit is 140, not real keen on blowing 2/3rds of that on a library that either makes scripts larger than they need to be via broken methodologies, or add “gee ain’t it neat” nonsense that interferes with accessibility, usability and pretty much flushes perfectly good websites down the toilet.

    • ikromm

      If you like spending your time and bandwidth go ahead and do so.
      It’s your money after all.
      FYI, that “trash scripting” is provided by Google and used in commercial applications by many big companies, including Google.
      Let those companies know this stuff bit better than you.
      In any case, if you want to convince us not to use jQuery or any other library, go ahead and provide correct arguments not just some sentences that make no sense or may seem better to you.
      There are numerous articles in this site that explain why this library is worthy of getting to know and using in your software.
      And above all, please stop whining.
      Back on topic, the article was very informative.
      Keep up the good work Sitepoint.

      • zippy

        And who wants to manually put a bunch of classes on page elements? Does deathshadow like incredibly mundane, and essentially pointless work?

        I know we should ALL get out more but I think maybe deathshadow is in more need of fresh air than the rest of us.

    • lifeshadow

      LOL! You really add a class to every other row to make alternating rows? What if you have like 40+ rows? What if you need to add a row later at position 2? You then waste your time changing all the following rows?

      How about just using jQuery to add the class to every even row, and save yourself a ton of hassle?

      Ha ha… Do you also take notes on paper? Pay bills through the mail? Technology is great once you learn to use it.

  • Avangelist

    It’s great you have written something but I can’t help but feel you have made a very basic concept seem incredibly complicated.

    You could have wrapped it up in two paragraphs.

    jquery allows you to filter elements on the page by tag name, any given attribute, or using css selectors in the same way you would in a css document.

    Not so hard was it.

  • Stormrider

    You have random em tags appearing inside the code blocks instead of the changed code

    • http://www.onsman.com Ricky Onsman

      Thanks, Stormrider. Fixed.

  • andersaloof

    Nice article, but there seems to be some typos in two of the example scripts. The selectors is said to be ‘#celebs tr’ and ‘#celebs tbody tr‘, but the correct should be ‘#celebs tbody tr’ and ‘#celebs tbody tr:even’….

  • Cadu Goncalves

    It would be great give the right credits here, mentioning in the article that in fact all this features, under the hood, are provided by Sizzle
    (http://sizzlejs.com/) which is embedded inside JQuery.
    JQuery is not a silver bullet ;)