Working with multiple sets of elements
Unlike with a single set
of elements, when we apply effects to different sets, they occur at
virtually the same time. To see these simultaneous effects in action,
we'll slide one paragraph down while sliding another paragraph up.
First, we'll add the remaining portion of the Gettysburg Address to the
HTML, dividing it into two separate paragraphs:
<div id="switcher">
<div class="label">Text Size</div>
<button id="switcher-default">Default</button>
<button id="switcher-large">Bigger</button>
<button id="switcher-small">Smaller</button>
</div>
<div class="speech">
<p>Fourscore and seven years ago our fathers brought forth
on this continent a new nation, conceived in liberty, and
dedicated to the proposition that all men are created
equal.
</p>
<p>Now we are engaged in a great civil war, testing whether
that nation, or any nation so conceived and so dedicated,
can long endure. We are met on a great battlefield of
that war. We have come to dedicate a portion of that
field as a final resting-place for those who here gave
their lives that the nation might live. It is altogether
fitting and proper that we should do this. But, in a
larger sense, we cannot dedicate, we cannot consecrate,
we cannot hallow, this ground.
</p>
<a href="#" class="more">read more</a>
<p>The brave men, living and dead, who struggled
here have consecrated it, far above our poor
power to add or detract. The world will little
note, nor long remember, what we say here, but it
can never forget what they did here. It is for us
the living, rather, to be dedicated here to the
unfinished work which they who fought here have
thus far so nobly advanced.
</p>
<p>It is rather for us to be here dedicated to the
great task remaining before us—that from
effectsmultiple set elements, working withthese honored dead we take increased devotion to
that cause for which they gave the last full
measure of devotion—that we here highly
resolve that these dead shall not have died in
vain—that this nation, under God, shall
have a new birth of freedom and that government
of the people, by the people, for the people,
shall not perish from the earth.
</p>
</div>
Next, to help us see what's
happening during the effect, we'll give the third paragraph a 1-pixel
border and the fourth paragraph a gray background. We'll also hide the
fourth paragraph when the DOM is ready:
$(document).ready(function() {
$('p:eq(2)').css('border', '1px solid #333');
$('p:eq(3)').css('backgroundColor', '#ccc').hide();
});
Finally, we'll add the .click()
method to the third paragraph so that when it is clicked, the third
paragraph will slide up (and out of view), while the fourth paragraph
slides down (and into view):
$(document).ready(function() {
$('p:eq(2)')
.css('border', '1px solid #333')
.click(function() {
$(this).slideUp('slow')
.next().slideDown('slow');
});
$('p:eq(3)').css('backgroundColor', '#ccc').hide();
});
A screenshot of these two effects in mid-slide confirms that they do, indeed, occur virtually simultaneously:
The third paragraph, which
started visible, is halfway through sliding up at the same time as the
fourth paragraph, which started hidden, is halfway through sliding down.
Callbacks
In order to allow queuing effects on different elements, jQuery provides a callback function for each effect method. As we have seen with event handlers and with the .queue()
method, callbacks are simply functions passed as method arguments. In
the case of effects, they appear as the last argument of the method.
If we use a callback to
queue the two slide effects, we can have the fourth paragraph slide down
before the third paragraph slides up. Let's first look at how to set up
the .slideDown() method with the callback:
$(document).ready(function() {
$('p:eq(2)')
.css('border', '1px solid #333')
.click(function() {
$(this).next().slideDown('slow',function() {
// code here executes after 3rd paragraph's
// slide down has ended
});
});
$('p:eq(3)').css('backgroundColor', '#ccc').hide();
});
We do need to be careful here, however, about what is actually going to slide up. The context has changed for $(this) because the callback is inside the .slideDown() method. Here, $(this) is no longer the third paragraph, as it was at the point of the .click() method; rather, since the .slideDown() method is attached to $(this).next(), everything within that method now sees $(this) as the next sibling, or the fourth paragraph. Therefore, if we put $(this).slideUp('slow') inside the callback, we would end up hiding the same paragraph that we had just made visible.
A simple way to keep the reference of $(this) stable is to store it in a variable right away within the .click() method, like var $thirdPara = $(this).
Now $thirdPara will
refer to the third paragraph, both outside and inside the callback. Here
is what the code looks like using our new variable:
$(document).ready(function() {
var $thirdPara = $('p:eq(2)');
$thirdPara
.css('border', '1px solid #333')
.click(function() {
$(this).next().slideDown('slow',function() {
$thirdPara.slideUp('slow');
});
});
$('p:eq(3)').css('backgroundColor', '#ccc').hide();
});
Using $thirdPara inside the .slideDown() callback relies on the properties of closures. We'll be discussing this important, yet difficult-to-master, topic in Appendix C.
This time, a snapshot
halfway through the effects will reveal that both the third and the
fourth paragraphs are visible; the fourth has finished sliding down and
the third is about to begin sliding up:
Instead of using the .queue() method, as we did earlier, we can simply use a callback function:
$(document).ready(function() {
$('div.label').click(function() {
var paraWidth = $('div.speech p').outerWidth();
var $switcher = $(this).parent();
var switcherWidth = $switcher.outerWidth();
$switcher
.fadeTo('slow',0.5)
.animate({
'left': paraWidth - switcherWidth
}, 'slow')
.fadeTo('slow',1.0)
.slideUp('slow', function() {
$switcher
.css('backgroundColor', '#f00');
})
.slideDown('slow');
});
jQuerycallback function, using});
Here again, the background color of<div id="switcher"> changes to red after it slides up, and before it slides back down.
In a nutshell
With all the
variations to consider when applying effects, it can become difficult to
remember whether the effects will occur simultaneously or sequentially.
A brief outline might help:
1. Effects on a single set of elements are:
simultaneous when applied as multiple properties in a single .animate() method
queued when applied in a chain of methods, unless the queue option is set to false
2. Effects on multiple sets of elements are: