JQuery: Novice to Ninja- P4

JQuery: Novice to Ninja- P4

JQuery: Novice to Ninja- P4:No matter what kind of ninja you are—a cooking ninja, a corporate lawyer ninja, or an actual ninja ninja—virtuosity lies in first mastering the basic tools of the trade. Once conquered, it’s then up to the full-fledged ninja to apply that knowledge in creative and inventive ways.

Nội dung Text: JQuery: Novice to Ninja- P4

22 jQuery: Novice to Ninja
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 select­
ors to narrow your selection even further.
Licensed to JamesCarlson@aol.com
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

Selecting, Decorating, and Enhancing 23
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:
chapter_02/02_selecting/script.js
$(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
Licensed to JamesCarlson@aol.com
narrowing down our selector to find only table rows that lie inside the tbody element:
chapter_02/03_narrowing_selection/script.js
$(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
table 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:

24 jQuery: Novice to Ninja
chapter_02/04_filters/script.js
$(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,
Licensed to JamesCarlson@aol.com
:eq() (for selecting, for example, the third element), and more. We’ll look at each
of these in more detail as we need them throughout the book.
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 satis­
fying 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 ele­
ments, the element name, id, and class are the most efficient and easiest ways to
achieve this.

Selecting, Decorating, and Enhancing 25
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 tech­
niques as we implement them in our examples and demos. For this reason, any time
Licensed to JamesCarlson@aol.com
you want to find out more about all the jQuery selectors available, you can just head
over to the online documentation1 and browse away!
Decorating: CSS with jQuery
Selecting elements in jQuery is the hard part. Everything else is both easy and fun.
After we have selected our targets, we are able to manipulate them to build effects
or interfaces. In this section we will cover a series of jQuery actions relating to CSS:
adding and removing styles, classes, and more. The actions we execute will be ap­
plied individually to every element we’ve selected, letting us bend the page to our
will!
Reading CSS Properties
Before we try changing CSS properties, let’s look first into how we can simply access
them. jQuery lets us do this with the css function. Try this:
chapter_02/05_reading_css_properties/script.js
$(document).ready(function() {
var fontSize = $('#celebs tbody tr:first').css('font-size');
alert(fontSize);
});
1
http://api.jquery.com/category/selectors/

26 jQuery: Novice to Ninja
This code will alert the font size of the first element matched by the selector (as
you’ve likely guessed, the :first filter will return the first element among those
matched by the selector).
CSS Properties of Multiple Elements
You can ask for a CSS property after selecting multiple elements, but this is almost
always a bad idea: a function can only return a single result, so you’ll still only
obtain the property for the first matched element.
The nifty aspect about retrieving CSS properties with this method is that jQuery
gives you the element’s calculated style. This means that you’ll receive the value
Licensed to JamesCarlson@aol.com
that’s been rendered in the user’s browser, rather than the value entered in the CSS
definition. So, if you gave a div a height of, say, 200 pixels in the CSS file, but the
content inside it pushed the height over 200 pixels, jQuery would provide you with
the actual height of the element, rather than the 200 pixels you’d specified.
We’ll see why that’s really important when we come to implement some funky
tricks a bit later.
Setting CSS Properties
So far we’ve yet to see jQuery actually do anything, and it’s high time to remedy
that. We know the page is ready (since we popped up an alert), and we’re fairly sure
we’ve selected the elements we’re interested in. Let’s check that we really have:
chapter_02/06_zebra_striping/script.js
$(document).ready(function() {
$('#celebs tbody tr:even').css('background-color','#dddddd');
});
You probably saw that coming! This is the same css function we used to read a CSS
property, but now it’s being passed an extra parameter: the value we wish to set for
that property. We’ve used the action to set the background-color to the value
#dddddd (a light gray). Open the file from the code archive in your browser and test
that it’s working correctly. You can see the result in Figure 2.2.

Selecting, Decorating, and Enhancing 27
Figure 2.2. Zebra striping implemented with jQuery
Licensed to JamesCarlson@aol.com
Were You Ready?
As mentioned previously, this command must be issued from within our document-
ready function. If we run the command before the DOM is ready, the selector will
go looking for the #celebs element, but will find nothing that matches. At this
point it will give up; it won’t even look for the tr elements, let alone change the
background style.
This is true for all of the examples that follow, so remember to wrap your code in
the document-ready function.
It’s looking good! But perhaps we should add a little extra to it—after all, more is
more! What about a shade lighter font color to really define our stripes? There are
a few ways we could add a second CSS property. The simplest way is to repeat the
entire jQuery statement with our new values:
chapter_02/07_multiple_properties_1/script.js (excerpt)
$('#celebs tbody tr:even').css('background-color','#dddddd');
$('#celebs tbody tr:even').css('color', '#666666');
These lines are executed one after the other. Though the end result is correct, it will
become quite messy and inefficient if we have to change a whole slew of properties.
Thankfully, jQuery provides us with a nice way to set multiple properties at the
same time, using an object literal. Object literals are a JavaScript concept beyond
the scope of this book, but for our purposes, all you need to know is that they provide
an easy way of grouping together key/value pairs. For CSS, object literals allow us

28 jQuery: Novice to Ninja
to match up our CSS properties (the keys) with the matching CSS values (the values)
in a neat package:
chapter_02/08_multiple_properties_2/script.js (excerpt)
$('#celebs tbody tr:even').css(
{'background-color': '#dddddd', 'color': '#666666'}
);
The object literal is wrapped in curly braces, with each key separated from its cor­
responding value by a colon, and each key/value pair separated by a comma. It’s
passed as a single parameter to the css function. Using this method you can specify
as many key/value pairs as you like—just separate them with commas. It’s a good
Licensed to JamesCarlson@aol.com
idea to lay out your key/value pairs in a readable manner so you can easily see
what’s going on when you come back to your code later. This is especially helpful
if you need to set a larger number of properties. As an example:
chapter_02/09_multiple_properties_3/script.js (excerpt)
$('#celebs tbody tr:even').css({
'background-color': '#dddddd',
'color': '#666666',
'font-size': '11pt',
'line-height': '2.5em'
});
To Quote or Not to Quote
In general, when dealing with JavaScript objects, it’s unnecessary for the keys to
be in quotes. However, for jQuery to work properly, any key that contains a hyphen
(as our background-color and font-size examples do) must be placed in
quotes, or written in camel case (like backgroundColor).
Additionally, any key that’s already a keyword in the JavaScript language (such
as float and class) must also be written in quotes.
It can be confusing trying to remember which keys need to be quoted and which
don’t, so it’s to be recommended that you just put all object keys in quotes each
time.

Selecting, Decorating, and Enhancing 29
Classes
Excellent! We’ve already struck two tasks off the client’s list, and we have some
funky jQuery happening. But if you stop and have a look at our last solution, you
might notice something a little fishy. If you were to inspect the zebra-striped rows
in a development tool such as Firebug, you’d notice that the CSS properties have
been added to the paragraphs inline, as illustrated in Figure 2.3.
Licensed to JamesCarlson@aol.com
Figure 2.3. Inline styles viewed with Firebug
Firebug
Firebug is a particularly useful tool for examining the DOM in your browser, as
well as monitoring and editing CSS, HTML, and JavaScript (including jQuery). A
debugger’s Swiss Army knife for the Web, it will save you hours by helping you
see exactly what your browser thinks is going on. It’s available as a Mozilla Firefox
extension, or as a stand-alone JavaScript file that you can include in your projects
if you develop using another browser.
Inline styles are a big no-no in HTML/CSS best practice, right? That’s quite true,
and this also applies in jQuery: to keep your code clear and maintainable, it makes
more sense for all the styling information to be in the same place, in your CSS files.
Then, as we’ll soon see, you can simply toggle those styles by attaching or removing
class attributes to your HTML tags.
There are times when it is a good idea to use the css jQuery method in the way
we’ve just seen. The most common application is when quickly debugging code: if

30 jQuery: Novice to Ninja
you just want to outline an element in red to make sure you’ve selected it correctly,
switching to your CSS file to add a new rule seems like a waste of time.
Adding and Removing Classes
If we need to remove the CSS from inline style rules, where should we put it? In a
separate style sheet, of course! We can put the styles we want in a rule in our CSS
that’s targeted to a given class, and use jQuery to add or remove that class from
targeted elements in the HTML. Perhaps unsurprisingly, jQuery provides some
handy methods for manipulating the class attributes of DOM elements. We’ll use
the most common of these, addClass, to move our zebra stripe styles into the CSS
file where they belong.
Licensed to JamesCarlson@aol.com
The addClass function accepts a string containing a class name as a parameter.
You can also add multiple classes at the same time by separating the class names
with a space, just as you do when writing HTML:
$('div').addClass('class_name');
$('div').addClass('class_name1 class_name2 class_name3');
We only want to add one class name, though, which we’ll call zebra. First, we’ll
add the rule to a new CSS file (including it with a link tag in our HTML page):
chapter_02/10_adding_classes/zebra.css
.zebra {
background-color: #dddddd;
color: #666666;
}
Then, back in our JavaScript file, we’ll modify the selector to use jQuery’s addClass
method rather than css:
chapter_02/10_adding_classes/script.js
$('#celebs tr:even').addClass('zebra');
The result is exactly the same, but now when we inspect the table in Firebug, we’ll
see that the inline styles are gone—replaced by our new class definition. This is
shown in Figure 2.4.

Selecting, Decorating, and Enhancing 31
Licensed to JamesCarlson@aol.com
Figure 2.4. Adding classes to table rows
That’s much better. Now, if we want to change the appearance of the zebra stripes
in the future, we can simply modify the CSS file; this will save us hunting through
our jQuery code (potentially in multiple locations) to change the values.
There’ll also be times when we want to remove class names from elements (we’ll
see an example of when this is necessary very soon). The action to remove a class
is conveniently known as removeClass. This function is used in exactly the same
way as addClass; we just pass the (un)desired class name as a parameter:
$('#celebs tr.zebra').removeClass('zebra');
It’s also possible to manipulate the id attribute, or any other attribute for that matter,
using jQuery’s attr method. We’ll cover this method in more detail later in the
book.
Enhancing: Adding Effects with jQuery
Now you’ve reached an important milestone. You’ve learned the component parts
of a jQuery statement: the selector, the action, and the parameters. And you’ve
learned the steps to use the statement: make sure the document is ready, select
elements, and change them.
In the following section, we’ll apply these lessons to implement some cool and
useful effects—and with any luck reinforce your understanding of the jQuery basics.

32 jQuery: Novice to Ninja
Hiding and Revealing Elements
The client dislikes the disclaimer on the site—he feels it reflects badly on the
product—but his lawyer insists that it’s necessary. So the client has requested that
you add a button that will remove the text after the user has had a chance to read
it:
chapter_02/11_hiding/index.html (excerpt)
We’ve added an HTML button on the page with an ID of hideButton. When a user
clicks on this button we want the disclaimer element, which has an ID of disclaimer,
Licensed to JamesCarlson@aol.com
to be hidden:
chapter_02/11_hiding/script.js (excerpt)
$('#hideButton').click(function() {
$('#disclaimer').hide();
});
Run this code and make sure the disclaimer element disappears when you click the
hide button.
The part in this example that makes the element actually disappear is the hide action.
So, you might ask, what’s all the other code that surrounds that line? It’s what’s
called an event handler—an understanding of which is crucial to becoming a jQuery
ninja. There are many event handlers we can use (we’ve used the click event
handler here) and we’ll be using a lot of them as we move on.
Event Handlers
Event handlers are named for their function of handling events. Events are actions
and user interactions that occur on the web page. When an event happens, we say
that it has fired. And when we write some code to handle the event, we say we
caught the event.
There are thousands of events fired on a web page all the time: when a user moves
the mouse, or clicks a button, or when a browser window is resized, or the scroll
bar moved. We can catch, and act on, any of these events.

Selecting, Decorating, and Enhancing 33
The first event that you were introduced to in this book was the document-ready
event. Yes, that was an event handler: when the document said, “I’m ready” it fired
an event, which our jQuery statement caught.
We used the click event handler to tell jQuery to hide the disclaimer when the
button is clicked:
$('#hideButton').click(function() {
$('#disclaimer').hide();
});
this
Licensed to JamesCarlson@aol.com
When an event fires, we will often want to refer to the element that fired it. For ex­
ample, we might want to modify the button that the user has just clicked on in some
way. Such a reference is available inside our event handler code via the JavaScript
keyword this. To convert the JavaScript object to a jQuery object, we wrap it in the
jQuery selector:
chapter_02/12_this/script.js (excerpt)
$('#hideButton').click(function() {
$(this).hide(); // a curious disappearing button.
});
$(this) provides a nicer way to talk about the element that fired the event, rather
than having to re-select it.
Where’s the Action?
This might be a bit confusing when you’re starting out, as the “action” component
of a jQuery statement seems to have several purposes: we’ve seen it used to run
animations, retrieve values and now, handle events! It’s true—it gets around!
Usually the action’s name gives you a good clue to its purpose, but if you become
lost, it’s best to consult the index. After a while, you’ll sort out the handlers from
the animations from the utilities.

34 jQuery: Novice to Ninja
Revealing Hidden Elements
On with our task! The client has also specified that the user needs to be able to re­
trieve the disclaimer in case they close it by mistake. So let’s add another button to
the HTML, this time with an id of showButton:
chapter_02/13_revealing/index.html (excerpt)
We’ll also add another jQuery statement to our script file, to handle showing the
disclaimer when the show button is clicked:
Licensed to JamesCarlson@aol.com
chapter_02/13_revealing/script.js (excerpt)
$('#showButton').click(function() {
$('#disclaimer').show();
});
Toggling Elements
Having separate buttons for hiding and showing the disclaimer seems like a waste
of valuable screen real estate. It would be better to have one button that performed
both tasks—hiding the disclaimer when it’s visible, and showing it when it’s hidden.
One way we could do this is by checking if the element is visible or not, and then
showing or hiding accordingly. We’ll remove the old buttons and add this nice new
one:
chapter_02/14_toggle_1/index.html (excerpt)
When it’s clicked, we check to find out if we should show or hide the disclaimer:
chapter_02/14_toggle_1/script.js (excerpt)
$('#toggleButton').click(function() {
if ($('#disclaimer').is(':visible')) {
$('#disclaimer').hide();
} else {

Selecting, Decorating, and Enhancing 35
$('#disclaimer').show();
}
});
This introduces the is action. is takes any of the same selectors we normally pass
to the jQuery function, and checks to see if they match the elements it was called
on. In this case, we’re checking to see if our selected #disclaimer is also selected
by the pseudo-selector :visible. It can also be used to check for other attributes:
if a selection is a form or div, or is enabled.
The if Statement
Licensed to JamesCarlson@aol.com
If you’re entirely new to programming (that is, if you’ve only ever worked with
HTML and CSS), that whole block of code is probably quite confusing! Don’t
worry, it’s actually quite straightforward:
if (condition) {
// this part happens if the condition is true
} else {
// this part happens if the condition is false
}
The condition can be anything that JavaScript will evaluate to true or false.
This sort of structure is extremely common in any type of programming, and we’ll
be using it a lot for the rest of the book. If you’re uncomfortable with it, the best
way to learn is to play around: try writing different if / else blocks using jQuery’s
is action like the one we wrote above. You’ll get the hang of it in no time!
is will return true or false depending on whether the elements match the selector.
For our purposes we’ll show the element if it’s hidden, and hide it if it’s visible.
This type of logic—where we flip between two states—is called a toggle and is a
very useful construct.
Toggling elements between two states is so common that many jQuery functions
have a version that allows for toggling. The toggle version of show/hide is simply
called toggle, and works like this:

36 jQuery: Novice to Ninja
chapter_02/15_toggle_2/script.js (excerpt)
$('#toggleButton').click(function() {
$('#disclaimer').toggle();
});
Every time you click the button, the element toggles between visible and hidden.
It would be nice, however, if the button was labeled with a more useful word than
“toggle,” which might be confusing to our users. What if you want to toggle the text
of the button as well? As is often the case when working with jQuery, there are a
few ways we could approach this problem. Here’s one:
Licensed to JamesCarlson@aol.com
chapter_02/16_toggle_text/script.js (excerpt)
$('#toggleButton').click(function() {
$('#disclaimer').toggle();
if ($('#disclaimer').is(':visible')) {
$(this).val('Hide');
} else {
$(this).val('Show');
}
});
There’s a lot in this code that will be new to you. We’ll save most of the details for
later, but have a look at it and see if you can figure it out yourself. (Hint: remember
that the selector $(this) refers to the element that caused the event to fire—in this
case, the button.)
Progressive Enhancement
Our disclaimer functionality is working perfectly—and our client will doubtlessly
be impressed with it. However, there’s one subtle aspect of our solution that we
should be aware of: if a user came to our site using a browser lacking support for
JavaScript, they’d see a button on the page that would do nothing when they clicked
it. This would lead to a very confused user, who might even abandon our site.
“No support for JavaScript?” you might snort. “What kind of browser is unable to
run JavaScript?!”