In This Chapter
Setting up for animation
Hiding and showing elements with jQuery
Fading elements in and out
Adding a callback function to a transition
Understanding object chaining
Using selection filters
Getting Prepared for Animation
To get your jQuery animation career started, take a look at hideShow.html, shown in Figure 11-1.
The hideShow program looks simple at first, but it does some very interesting things. All of the level-two headings are actually buttons, so when you click them, fun stuff happens:
The Show button displays a previously hidden element. Figure 11-2 demonstrates the new content.
The Hide button hides the content. The behavior of the hide button is pretty obvious. If the content is showing, clicking the button makes it disappear instantly.
The Toggle button swaps the visibility of the content. If the content is currently visible, clicking the button hides it. If it is hidden, a click of the button makes it show up.
At first, the page shows nothing much.
‘ The Slide Down button makes the content transition in. The slide down transition acts like a window shade being pulled down to make the content visible through a basic animation.
The Slide Up button transitions the content out. This animation looks like a window shade being pulled up to hide the content.
The Fade In button allows the element to dissolve into visibility. This animation looks much like a fade effect used in video. As in the sliding animations, you can control the speed of the animation.
A special function is called when the fade in is complete. In this example, I call a function named present as soon as the fade in is complete. This is a callback function, which I explain in just a bit.
The Fade Out button fades the element to the background color. This technique gradually modifies the opacity of the element so it gradually disappears.
Here are a couple of details for you to keep in mind:
You can adjust how quickly the transition animation plays. For example,
the hideShow program plays the slide down at a slow speed, and slide up faster. You can even specify exactly how long the transition takes in milliseconds (1/1000ths of a second).
‘ Any transition can have a callback function attached. A callback function is a function that will be triggered when the transition is complete.
Of course, the showHide example relies on animation, which isn’t easy to see in a static topic. Please be sure to look at this and all other example Better yet, install them on your own machine and play around with my code until they make sense to you.
The content element is now visible.
The animations shown in this example are useful when you want to selectively hide and display parts of your page. Being able to show and hide elements is useful in a number of situations. Menus are one obvious use. You might choose to store your menu structure as a series of nested lists, displaying parts of the menu only when the parent is activated. Another common use of this technology is to have small teaser sentences that expand to show more information when the user clicks or hovers the mouse pointer over them. This technique is commonly used on blog and news sites to let users preview a large number of topics, kind of like a text-based thumbnail image.
The jQuery library has built-in support for transitions that make these effects pretty easy to produce. Look over the entire hideShow.html program before digging in on the details.
This example might look long and complicated when you view it all at once, but it isn’t hard to understand when you break it into pieces. The following sections help you get comfortable with this example.
Writing the HTML and CSS foundation
The HTML used in this example is minimal, as is common in jQuery development. It consists of a single level-one heading, a series of level-two headings, and a paragraph. The level-two headings will be used as buttons in this example. I use a CSS style to make the <h2> tags look more like buttons (adding a border and background color). I added an id attribute to every button so I can add jQuery events later.
If I wanted the h2 elements to look and act like buttons, why didn’t I just make them with button tags in the first place? That’s a very good question. At one level, I probably should use the semantically clear button tag to make a button. However, in this example, I want to focus on the jQuery and keep the HTML as simple as possible. jQuery can help you make any element act like a button, so that’s what I did. Users don’t expect h2 elements to be clickable, so you need to do some styling (as I did) to help the users understand that they can click the element. For comparison purposes, the other two examples in this chapter use actual HTML buttons.
The other interesting part of the HTML is the content div. In this example, the actual content isn’t really important, but I did add some CSS to make the content very easy to see when it pops up. The most critical part of the HTML from a programming perspective is the inclusion of the id attribute. This attribute makes it easy for a jQuery script to manipulate the component so that it hides and reappears in various ways. Note that the HTML and CSS does nothing to hide the content. It will be hidden (and revealed) entirely through jQuery code.
Initializing the page
The initialization sequence simply sets the stage and assigns a series of event handlers:
The pattern for working with jQuery should now be familiar:
1. Set up an initialization function.
Use the $(document).ready() mechanism described in Chapter 12 or this cleaner shortcut to specify an initialization function.
2. Hide the content div.
When the user first encounters the page, the content div should be hidden.
3. Attach event handlers to each h2 button.
This program is a series of small functions. The init() function attaches each function to the corresponding button. Note how I carefully named the functions and buttons to make all the connections easy to understand.
Working with callback functions
This technique is heavily used in jQuery programming. When you define an event, you will often specify a function that should be called when that event is triggered. Such a function is often referred to as a callback function.
In this context, the function name is treated as a variable, so it doesn’t need the parentheses you normally use when referring to functions.
Hiding and Showing the Content
Each of these functions works in the same basic manner:
1. Identify the content div.
Create a jQuery node based on the content div. If you need more information on creating jQuery node objects, please check Chapter 10.
2. Hide or show the node.
The jQuery object has built-in methods for hiding and showing.
The hide() and show() methods act instantly. If the element is currently visible, the show() method has no effect. Likewise, hide() has no effect on an element that’s already hidden.
The following sections describe some fun tricks for revealing or concealing elements.
In addition to hide() and show(), the jQuery object supports a toggle() method. This method takes a look at the current status of the element and changes it. If the element is currently hidden, clicking the button makes it visible. If it’s currently visible, clicking the button hides it. The toggle Content() function illustrates how to use this method:
Sliding an element
jQuery supports a window blind effect that allows you to animate the appearance and disappearance of your element. The general approach is very similar to hide() and show() , but the effect has one additional twist:
The slideDown() method makes an element appear like a window shade being pulled down. The slideUp() method makes an element disappear in a similar manner. These functions take a speed parameter that indicates how quickly the animation occurs. The speed can be a string value (“fast”, “medium”, or “slow”) or a numeric value in milliseconds (measured in 1,000th of a second). The value 50 0 means 500 milliseconds, or half a second. If you leave out the speed parameter, the default value is “medium”.
The show(), hide(), and toggle() methods also accept a speed parameter. In these functions, the object shrinks and grows at the indicated speed.
There is also a slideToggle() function available that toggles the visibility of the element, but using the sliding animation technique.
Fading an element in and out
Another type of animation is provided by the fade methods. These techniques adjust the opacity of the element. The code should look quite familiar by now:
fadeIn() and fadeout() work just like the hide() and slide() techniques. The fading techniques adjust the opacity of the element and then remove it, rather than dynamically changing the size of the element as the slide and show techniques do.
I’ve added one more element to the fadeIn() function. If you supply the fadeIn() method (or indeed any of the animation methods described in this section) with a function name as a second parameter, that function is a callback function, meaning it is called upon completion of the animation. When you click the fade in button, the content div slowly fades in, and then when it is completely visible, the present() function gets called. This function doesn’t do a lot in this example — it simply pops up an alert — but it could be used to handle some sort of instructions after the element is visible.
If the element is already visible, the callback method will be triggered immediately.
Changing an Element’s Position With jQuery
The jQuery library also has interesting features for changing any of an element’s characteristics, including its position. The animate.html page featured in Figure 11-3 illustrates a number of interesting animation techniques.
You know what I’m going to say, right? This program moves things around. You can’t see that in a topic. Be sure to look at the actual page. Trust me; it’s a lot more fun than it looks in this screen shot.
Click the buttons, and the element moves. (I added the arrow to indicate motion.)
This page (animate.html) illustrates how to move a jQuery element by modifying its CSS. (Check Bonus Chapter 2 on the Web site if you’re unfamiliar with CSS.) It also illustrates an important jQuery technique called object chaining as well as a very useful animation method that allows you to create smooth motion over time. Look over the entire code first, and then in the following sections I break it into sections for more careful review:
Creating the HTML framework
Note that I use < in one of the button captions. (You can find it near the end of the animate.html listing.) This HTML attribute displays the less-than symbol. Had I used the actual symbol (<) the browser would have thought I was beginning a new HTML tag and would have been confused.
The buttons all have id attributes, but I didn’t attach functions to them with the onclick attribute. When you’re using jQuery, it makes sense to commit to a jQuery approach and use the jQuery event techniques.
The only other important HTML element is the content div. Once again, this element is simply a placeholder, but I added CSS styling to make it obvious when it moves around. It’s important that you set this element to be absolutely positioned, because the position will be changed dynamically in the code.
Setting up the events
The initialization is all about setting up the event handlers for the various buttons. Begin with an init() function called when the document is ready. That function contains callback functions (such as move and glide) for the various events, directing traffic to the right functions when a user presses a button:
As usual, naming conventions make it easy to see what’s going on.
Don’t go chaining
jQuery supports a really neat feature called node chaining that allows you to put several steps into one single line. This makes your code a lot easier to write, and it allows you to do several things to a particular element or group of elements at once. As an example, take another look at the move() function defined in animate.html.
The move function isn’t really that radical. All it really does is use the css() method described in Chapter 10 to alter the position of the element. After all, position is just a CSS attribute, right? Well, it’s a little more complex than that. The position of an element is actually stored in two attributes, top and left. Your first attempt at a move function would probably look like this:
Although this approach certainly works, it has a subtle problem. It moves the element in two separate steps. Although most browsers are fast enough to prevent this from being an issue, node chaining allows you to combine many jQuery steps into a single line.
Almost all jQuery methods return a jQuery object as a side effect. So, the line
not only changes the text of the content node, but actually makes a new node. You can attach that node to a variable like this if you want:
However, what most jQuery programmers do is simply attach new functionality onto the end of the previously defined node, like this:
This new line takes the node created by $(“#content”) and changes its text value. It then takes this new node (the one with changed text) and adds a click event to it, calling the hiThere() function when the content element is clicked. In this way, you build an ever-more complex node by chaining nodes on top of each other.
Note that only the last line has a semicolon because what’s shown is all one line of logic even though it occurs on three lines in the editor.
Building the move() function with chaining
Object chaining makes it easy to build the move function so that it moves the content’s left and top properties simultaneously:
This function uses the css() method to change the left property to 50px. The resulting object is given a second css() method call to change the top property to 10 0px. The top and left elements are changed at the same time as far as the user is concerned.
Building time-based animation with animate()
Using the css() method is a great way to move an element around on the screen, but the motion is instantaneous. jQuery supports a powerful method called animate(), which allows you to change any DOM characteristics over a specified span of time. The glide button on animate.html smoothly moves the content div from (50, 100) to (400, 200) over two seconds.
The function begins by moving the element immediately to its initial spot with chained css() methods. It then uses the animate() method to control the animation. This method can have up to three parameters:
A JSON object describing attributes to animate: The first parameter is an object in JSON notation describing name/value attribute pairs. In this example, I’m telling jQuery to change the left attribute from its current value to 400px and the top value to 200px. Any numeric value that you can change through the DOM can be included in this JSON object. Instead of a numerical value, you can use “hide”, “show”, or “toggle” to specify an action. Review Chapter 5 for more on JSON objects if you’re unfamiliar with them.
A speed attribute: The speed parameter is defined in the same way as the speed for fade and slide animations. There are three predefined speeds: “slow”, “medium”, and “fast”; speed can also be indicated in milliseconds (so 2000 means 2 seconds).
A callback function: This optional parameter describes a function to be called when the animation is complete. I describe the use of callback functions earlier in this chapter in the section called “Fading an element in and out.”
Move a little bit: Relative motion
You can use the animation mechanism to move an object relative to its current position. The arrow buttons and their associated functions perform this task:
These functions also use the animate() method, but there’s a small difference in the position parameters. The += and -= modifiers indicate that I want to add to or subtract from the value rather than indicating an absolute position. Of course, you can add as many parameters to the JSON object as you want, but these are a good start.
Note that since I’m moving a small amount (ten pixels) I want the motion to be relatively quick. Each motion lasts 100 milliseconds.
The jQuery animation() method supports one more option: easing. The term easing refers to the relative speed of the animation throughout its lifespan. If you watch the animations on the animate.html page carefully, you’ll see that the motion begins slowly, builds up speed, and slows down again at the end. This provides a natural-feeling animation. By default, jQuery animations use what’s called a swing easing style (slow on the ends, fast in the middle, like a child on a swing). If you want to have a more consistent speed, you can specify “linear” as the fourth parameter, and the animation will work at a constant speed. You can also install plugins for more advanced easing techniques.
Modifying Elements on the Fly
The jQuery library supports a third major way of modifying the page: the ability to add and remove contents dynamically. This is a powerful way to work with a page. The key to this feature is another of jQuery’s most capable tools: its flexible selection engine. You’ve already seen how you can select jQuery nodes using the standard CSS-style selectors, but you can also use numerous attributes to modify nodes. The changeContent.html page demonstrates some of the power of these tools (see Figure 11-4).
Of course, the buttons allow the user to make changes to the page dynamically. Pressing the Add Text button adds more text to the content area, as you can see in Figure 11-5.
The default state of change-Content is a little dull.
More text can be appended inside any content area.
The Clone button is interesting because it allows you to make a copy of an element and place it somewhere else in the document hierarchy. Pressing the Clone button a few times can give you a page like Figure 11-6.
It’s possible to wrap an HTML element around any existing element. The Wrap in Div button puts a div (with a red border) around every cloned element. You can press this multiple times to add multiple wrappings to any element. Figure 11-7 shows what happens after I wrap a few times.
For readability, sometimes you want to be able to alternate styles of lists and tables. jQuery offers an easy way to select every other element in a group and give it a style. The Change Alternate Paragraphs button activates some code that turns all odd-numbered paragraphs into white text with a green background. Look at Figure 11-8 for a demonstration.
Finally, the Reset button demonstrates how you can reset all the changes you made with the other buttons.
I’ve made several clones of the original content.
Now there’s a red-bordered div around all the cloned elements.
All odd-numbered paragraphs have a new style.
The code for changeContent.html seems complex, but it follows the same general patterns in jQuery programming that I show you earlier in this chapter. As always, look over the entire code first, and then I break it down.
I admit, this program has a lot of code, but when you consider how much functionality this page has, it really isn’t too bad. Look at it in smaller pieces, and it all make sense.
Building the basic page
As usual, begin by inspecting the HTML. The basic code for this page sets up the playground.
1. Create a form with buttons.
This form becomes the control panel. Add a button for each function you want to add. Make sure each button has an ID, but you don’t need to specify an onclick function, because the init() function will take care of that.
2. Build a prototype content div.
Build a div called content, and add a paragraph to the div.
Initializing the code
Adding text to a component is pretty easy. The append() method attaches text to the end of a jQuery node. Table 11-1 shows a number of other methods for adding text to a node.
|Table 11-1 Adding||Content to jQuery Nodes|
|append(text)||Adds the text (or HTML) to the end of the|
|prepend(text)||Adds the content at the beginning of the|
|insertAfter(text)||Adds the text after the selected element|
|(outside the element).|
|insertBefore(text)||Adds the text before the selected element|
|(outside the element).|
More methods are available, but these are the ones I find most useful. Be sure to check out the official documentation at http://docs.jquery.com to see the other options.
The append() method adds the new text to the end of the text already inside the element, so it becomes part of the paragraph contained inside the content div. For example, if you have this element: <div>one</div> and you append two to the div, you’ll get <div>onetwo</div>, not <div>one</ div>two.
The more interesting part of this code is the selector. It could read like this:
That would add the text to the end of the paragraph. The default text has only one paragraph, so that makes lots of sense. If there are more paragraphs (and there will be), the p selector will select them all, adding the text to all the paragraphs simultaneously. By specifying p:first, I’m using a special filter to determine exactly which paragraph should be affected. Many of the examples on this page use jQuery filters, so I describe them elsewhere in this section. For now, note that p:first means the first paragraph. Of course, there are also p:last and many more. Read on. . . .
Attack of the clones
You can clone (copy) anything you can identify as a jQuery node. This cloning makes a copy of the node without changing the original. The cloned node isn’t immediately visible on the screen. You need to place it somewhere, usually with an append(),prepend(), insertBefore(), or insertAfter() method.
Take a look at the clone() function to see how it works:
1. Select the first paragraph.
The first paragraph is the one I want to copy. (In the beginning, there’s only one, but that will change soon.)
2. Use the clone() method to make a copy.
Even though this step makes a copy, it still isn’t visible. Use chaining to do some interesting things to this copy. (I explain chaining earlier in the chapter, in the section “Don’t go chaining . . .”)
3. Add the new element to the page after the last paragraph.
The p:last identifier is the last paragraph, so insertAfter (“p:last”) means put the new paragraph after the last paragraph available in the document.
4. Change the CSS.
Just for grins, chain the css() method onto the new element and change the background color to light blue. This just reinforces that you can continue adding commands to a node through chaining.
Note that the paragraphs are still inside the content div. Of course, I could have put them elsewhere with careful use of selectors, but that’s where I want them.
Keeping track of changes to the page is difficult because a standard View Source command shows you the original source code, not the code that’s been changed by your jQuery magic. jQuery changes the HTML of your page in memory, but doesn’t change the text file that contains your page. If your page isn’t doing what you expect, you need to look at the script-generated source code to see what’s really going on. Firefox plugins are the key to headache-free debugging. The Web developer toolbar has a wonderful feature called View Generated Source (available under the View Source menu), which shows the page source as it currently exists in memory. If you prefer the Firebug extension, its inspect mode also inspects the page as it currently is displayed. Both tools are described in Chapter 1.
Note that the content of the first paragraph is cloned with its current content and style information copied to the new element. If you clone the paragraph and then add content to it and clone it again, the first clone has the default text, and the second clone contains the additional text. If you modify the CSS of an element and then clone it, the clone also inherits any of the style characteristics of the original node.
It’s a Wrap
The wrap method is pretty easy to understand. If you feed it any container tag, it wraps that container around the selected node. You can also use multiple elements, so if you want to enclose a paragraph into a single item list, you can do something like this:
The resulting code would surround each paragraph with an unordered list and list item.
Returning to the wrap function, I’ve decided not to wrap every paragraph with a div, just the ones that have been cloned. (Mainly I’m doing this so I can show you some other cool selection filters.) The selector p:gt(0) means “select all paragraphs with an index greater than zero.” In other words, ignore the first paragraph but apply the following methods to all other paragraphs. There is also a less-than filter (:lt), which isolates elements before a certain index, and an equals filter (:eq), which isolates an element with a certain index.
The :odd selector only chooses elements with an odd index and returns a jQuery node that can be further manipulated with chaining. Of course, you can use an :even selector for handling the even-numbered nodes. The rest of this code is simply CSS styling.
Resetting the page
If you can do all this modification to the page, you’ll also need to be able to restore it to its pristine state. A quick jQuery function can easily do the trick:
This function reviews many of the jQuery and selection tricks shown in this chapter.
1. Remove all but the first paragraph.
Any paragraphs with an index greater than zero is a clone, so it needs to go away. The remove() method removes all jQuery nodes associated with the current selector.
2. Remove all divs but the original content.
I could have used the :gt selector again, but instead I use another interesting selector: :not. This selector means “remove every div that isn’t the primary content div.” Using this selector removes all divs added through the wrap function.
3. Reset the original content div to its default text.
Set the default text back to its original status so the page is reset.
Truthfully, all I really need here is the last line of code. Changing the HTML of the content div replaces the current contents with whatever is included, so the first two lines aren’t entirely necessary in this particular context. Still, it’s very useful to know how to remove elements when you need to do so.
More fun With selectors and filters
The jQuery selectors and filters are really fun and powerful. Table 11-2 describes a few more filters and how you can use them.
|Table 11-2||Common jQuery Filters|
|:header||Any header tag (h1, h2, h3).|
|:animated||Any element that is currently being animated.|
|:contains(text)||Any element that contains the indicated text.|
|:empty||The element is empty.|
|:parent||This element contains some other element.|
|:attribute=value||The element has an attribute with the specified|
|:Input, :text,||Matches on the specific element type (especially|
|:radio, :image,||useful for form elements that are all variations of the|
|:button, and so on||input tag).|
Note that this is a representative list. Be sure to check out the official documentation at http://docs.jquery.com for a more complete list of filters.