Selecting by attributes (Should know)
In this section, we'll see how to select elements by their attributes paying attention to some quirks that can lead to an unexpected behavior.
Getting ready
These selectors are easily recognizable because they are wrapped by square brackets (for example, [selector]
). This type of selector is always used coupled with other, like those seen so far, although this can be implicit as we'll see in few moments. In my experience, you'll often use them with the Element selector, but this can vary based on your needs.
How many and what are the selectors of this type? Glad you asked! Here is a table that gives you an overview:
Name |
Syntax |
Description |
---|---|---|
Contains |
[attribute*="value"] (for example |
Selects the elements that have the value specified as a substring of the given attribute. |
Contains Prefix |
[attribute|="value"] (for example, |
Selects nodes with the given value equal or equal followed by a hyphen inside the specified attribute. |
Contains Word |
[attribute~="value"] (for example, |
Selects elements that have the specified attribute with a value equal to or containing the given value delimited by spaces. |
Ends With |
[attribute$="value"] (for example, |
Selects nodes having the value specified at the end of the given attribute's value. |
Equals |
[attribute="value"] (for example, |
Selects elements that have the specified attribute with a value equal to the given value delimited by spaces. This selector performs an exact match. |
Not Equal |
[attribute!="value"] (for example, |
Selects elements that don't have the specified attribute or have it but with a value not equal to the given value delimited by spaces. |
Starts With |
[attribute^="value"] (for example, |
Selects nodes having the value specified at the start of the given attribute's value. |
Has |
[attribute] (for example, |
Selects elements that have the attribute specified, regardless of its value. |
As you've seen in the several examples in the table, we've used all of these selectors with other ones. Recalling what I said few moments ago, sometimes you can have used them with an implicit selector. In fact, take the following example:
$('[placeholder]')
What's the "hidden" selector? If you guessed All, you can pat yourself on the back. You're really smart! In fact, it's equivalent to write:
$('*[placeholder]')
How to do it...
There are quite a lot of Attribute selectors, therefore, we won't build an example for each of them, and I'm going to show you two demos. The first will teach you the use of the Attribute Contains Word selector to print on the console the value of the collected elements. The second will explain the use of the Attribute Has selector to print the value of the placeholder's attribute of the retrieved nodes.
Let's write some code!
To build the first example, follow these steps:
Create a copy of the
template.html
file and rename it ascontain-word-selector.html
.Inside the
<body>
tag, add the following HTML markup:<h1>Rank</h1> <table> <thead> <th>Name</th> <th>Surname</th> <th>Points</th> </thead> <tbody> <tr> <td class="name">Aurelio</td> <td>De Rosa</td> <td class="highlight green">100</td> </tr> <tr> <td class="name">Nikhil</td> <td>Chinnari</td> <td class="highlight">200</td> </tr> <tr> <td class="name">Esha</td> <td>Thakker</td> <td class="red highlight void">50</td> </tr> </tbody> </table>
Edit the
<head>
section adding the following lines just after the<title>
:<style> .highlight { background-color: #FF0A27; } </style>
Edit the
<head>
section of the page adding this code:<script> $(document).ready(function() { var $elements = $('table td[class~="highlight"]'); console.log($elements.length); }); </script>
Save the file and open it with your favorite browser.
To create the second example, performs the following steps instead:
Create a copy of the
template.html
file and rename it ashas-selector.html
.Inside the
<body>
tag, add the following HTML markup:<form name="registration-form" id="registration-form" action="registration.php" method="post"> <input type="text" name="name" placeholder="Name" /> <input type="text" name="surname" placeholder="Surname" /> <input type="email" name="email" placeholder="Email" /> <input type="tel" name="phone-number" placeholder="Phone number" /> <input type="submit" value="Register" /> <input type="reset" value="Reset" /> </form>
Edit the
<head>
section of the page adding this code:<script> $(document).ready(function() { var $elements = $('input[placeholder]'); for(var i = 0; i < $elements.length; i++) { console.log($elements[i].placeholder); } }); </script>
Save the file and open it with your favorite browser.
How it works...
In the first example, we created a table with four rows, one for the header and three for the data, and three columns. We put some classes to several columns, and in particular, we used the class highlight
. Then, we set the definition of this class so that an element having it assigned, will have a red background color.
In the next step, we created our usual script (hey, this is still a book on jQuery, isn't it?) where we selected all of the <td>
having the class highlight
assigned that are descendants (in this case we could use the Child selector as well) of a <table>
. Once done, we simply print the number of the collected elements. The console will confirm that, as you can see by yourself loading the page, that the matched elements are three. Well done!
In the second step, we created a little registration form. It won't really work since the backend is totally missing, but it's good for our discussion. As you can see, our form takes advantage of some of the new features of HTML5, like the new <input>
types e-mail
and tel
and the placeholder attribute.
In our usual handler, we're picking up all of the <input>
instance's in the page having the placeholder
attribute specified and assigning them to a variable called $elements
. Recalling what we learned in the Selecting by id (Must know) recipe, we're prepending a dollar sign to the variable name to highlight that it stores a jQuery object. With the next block of code, we iterate over the object to access the elements by their index position. Then we log on the console the placeholder's value accessing it using the dot operator. As you can see, we accessed the property directly, without using a method. This happens because the collection's elements are plain DOM elements and not jQuery objects. If you replicated correctly the demo you should see this output in your console:
In this recipe, we chose all of the page's <input>
instance's, not just those inside the form since we haven't specified it. A better selection would be to restrict the selection using the form's id, that is very fast as we've already discussed. Thus, our selection will turn into:
$('#registration-form input[placehoder]')
We can have an even better selection using the jQuery's find()
method that retrieves the descendants that matches the given selector:
$('#registration-form').find('input[placehoder]')
There's more...
You can also use more than one attribute selector at once.
Multiple attribute selector
In case you need to select nodes that match two or more criteria, you can use the Multiple Attribute selector. You can chain how many selectors you liked, it isn't limited to two.
Let's say that you want to select all of the <input>
instance's of type email
and have the placeholder
attribute specified, you would need to write:
$('input[type="email"][placeholder]')
Not equal selector
This selector isn't part of the CSS specifications, so it can't take advantage of the native querySelectorAll()
method. The official documentation has a good hint to avoid the problem and have better performance:
Tip
For better performance in modern browsers, use $("your-pure-css-selector").not('[name="value"]')
instead.
Using filter() and attr()
jQuery really has a lot of methods to help you in your work and thanks to this, you can achieve the same task in a multitude of ways. While the attribute selectors are important, it can be worth to see how you could achieve the same result seen before using filter()
and attr()
.
filter()
is a function that accepts only one argument that can be of different types, but you'll usually see codes that pass a selector or a function. Its aim is to reduce a collection, iterating over it, and keeping only the elements that match the given parameter. The attr()
method, instead, accepts up to two arguments and the first is usually an attribute name. We'll use it simply as a getter to retrieve the value of the elements' placeholder.
To achieve our goal, replace the selection instruction with these lines:
var $elements = $('#registration-form input').filter(function() { return ($(this).attr("placeholder") !== undefined) });
The main difference here is the anonymous function we passed to the filter()
method. Inside the function, this refers to the current DOM element processed, so to be able to use jQuery's methods we need to wrap the element in a jQuery object. Some of you may guess why we haven't used the plain DOM elements accessing the placeholder
attribute directly. The reason is that the result won't be the one expected. In fact, by doing so, you'll have an empty string as a value even if the placeholder
attribute wasn't set for that element making the strict test against undefined
useless.