This post is Part 6 in The Beginner’s Guide To Writing a jQuery Plugin.
At this point, we’ve created our simple slideshow plugin for jQuery and have built it in such a way that it follows jQuery’s model for plugin development and we’re ready to begin the second iteration of development.
For the second iteration, let’s plan on the following:
- We have some duplicate code in our plugin left from the previous iteration. We need to refactor that out.
- Let’s introduce some options that allow users to configure change the speed of the slideshow and whether or not they want a fade transition.
1. Refactoring
In the context of programming, refactoring refers to the changing of an application’s code without actually modifying any of its existing functionality.
If you take a look at the current state of our slideshow plugin, specifically within the setInterval() function, you’ll notice that we have some duplicate code:
[cc lang=”javascript”]
if($activeImage.next().length > 0) {
$(‘.activeImage’).hide()
.removeClass(‘activeImage’)
.next()
.show()
.addClass(‘activeImage’);
} else {
$(‘.activeImage’).hide()
.removeClass(‘activeImage’)
.siblings(‘:first’)
.show()
.addClass(‘activeImage’);
}
[/cc]
In both cases of the conditional, we’re hiding the active image, removing the class, displaying the next image, and then adding the activeImage class to it.
A good first step in refactoring your code is to find what’s duplicated and factor that out into its own function.
For us, both cases in the conditional are the same with the exception of which image to display next and that’s solely dependent on the result of the conditional statement.
With this, we know that we’re going to be performing the same behavior on two images – specifically, we’re swapping out the display of one image for another.
This sounds like a function. At the bottom of the plugin file, let’s stub out the following code:
[cc lang=”javascript”]
function swap($activeImage, $nextImage) {
// TODO
}
[/cc]
We’ve just created a function named swap that accepts two images. Notice that each argument is prefixed with a ‘$.’ This is a good practice as it lets us know that the incoming value is wrapped with the jQuery object.
Next, let’s take the duplicate code from the original plugin and include it here in our swap function:
[cc lang=”javascript”]
function swap($activeImage, $nextImage) {
$activeImage.hide().removeClass(‘activeImage’);
$nextImage.show().addClass(‘activeImage’);
}
[/cc]
Notice that the only change from above is that rather than making a call to the next sibling or the first sibling, we’re simply acting on the $nextImage. This will be taken care of in the conditional. Let’s update it to now use our new function:
[cc lang=”javascript”]
if($(‘.activeImage’).next().length > 0) {
swap($(‘.activeImage’), $(‘.activeImage’).next());
} else {
swap($(‘.activeImage’), $(‘.activeImage’).siblings(‘:first’));
}
[/cc]
At this point, we’ve completely refactoring the plugin – the external behavior hasn’t changed at all, but our code is much cleaner.
2. Introducing Options
Allowing users to pass options into your jQuery plugin is a relatively straightforward process. jQuery has a specific way in which this is achieved so it’s a matter of updating our plugin to support this functionality.
Options are passed into a plugin via what’s referred to as an options object – that is, an object that has an set of keys associated with specific values. For example, our options object will eventually look like this:
[cc lang=”javascript”]
{
fade: false,
speed: 1
}
[/cc]
In this example, the two keys are fade and speed and their respective values are false and 100.
To begin including support for options in our plugin, our makeSlideshow function must actually accept an options argument, so let’s add that:
[cc lang=”javascript”]
jQuery.fn.makeSlideshow = function(options) {
// …
}
[/cc]
Next, we need to specify the default options just in case a user doesn’t pass these options into the plugin. The default values should mimic the behavior that we have up to this point. That is, there should be no fading and the speed should be three seconds.
Right outside of the makeSlideshow() function, let’s define the default plugin options. This is done in exactly the same way as adding a custom function to jQuery:
[cc lang=”javascript”]
jQuery.fn.makeSlideshow = function(options) {
// …
}
jQuery.fn.makeSlideshow.defaults = {
fade: false,
speed: 3000
}
[/cc]
Next, we need to add one more line of code just before our plugin begins execution:
[cc lang=”javascript”]
jQuery.fn.makeSlideshow = function(options) {
var opts = jQuery.extend({}, jQuery.fn.makeSlideshow.defaults, options);
return this.each(function() {
// …
}
};
[/cc]
This line of code is creating a new object and then it’s literally merging the values from the default object that we created above with the options object that the user is passing in. This creates a new object that we can refer to by using the opts variable that we’ve defined at the beginning of the line of code. All of this is achieved via jQuery’s extend() function.
The opts variable is what will allow us to use the parameters – either those that are user specified or those that are the default – throughout our plugin.
3. Making Our Plugin Options Aware
Even though our plugin accepts options, we still haven’t changed any of the functionality so that it actually uses them.
First, let’s update the setInterval() function so that it uses the timing based on what the opts object maintains. Locate the 3000 value at the end of the setInterval function and replace it with the options value:
[cc lang=”javascript”]
setInterval(function() {
if($(‘.activeImage’).next().length > 0) {
swap($(‘.activeImage’), $(‘.activeImage’).next());
} else {
swap($(‘.activeImage’), $(‘.activeImage’).siblings(‘:first’));
}
}, opts.speed);
[/cc]
Next, we need to take advantage of jQuery’s fadeIn() and fadeOut() function. Recall in the first step, we created a swap() function that is responsible for displaying the images in the slideshow. This is where the fading should occur.
Let’s update our function to include an incoming option for fading:
[cc lang=”javascript”]
function swap($activeImage, $nextImage, shouldFade) {
if(shouldFade) {
$activeImage.fadeOut(function() {
$(this).removeClass(‘activeImage’);
$nextImage.fadeIn(function() {
$(this).addClass(‘activeImage’);
});
});
} else {
$activeImage.hide().removeClass(‘activeImage’);
$nextImage.show().addClass(‘activeImage’);
}
}
[/cc]
Next, let’s update the call to the swap function:
[cc lang=”javascript”]
setInterval(function() {
if($(‘.activeImage’).next().length > 0) {
swap($(‘.activeImage’), $(‘.activeImage’).next(), opts.fade);
} else {
swap($(‘.activeImage’), $(‘.activeImage’).siblings(‘:first’), opts.fade);
}
}, opts.speed);
[/cc]
Finally, we need to update the swap function so that if the user wants the slideshow to fade, then we leverage the fadeIn() and fadeOut() functions rather than the show() and hide() functions.
Once we’re in the swap function, we need a conditional that will check whether or not the user wants to fade. If so, then we should use the new functions; otherwise, we should use the exisitng functionality.
The first pass at the conditional will look like this:
[cc lang=”javascript”]
function swap($activeImage, $nextImage, shouldFade) {
if(shouldFade) {
// TODO
} else {
$activeImage.hide().removeClass(‘activeImage’);
$nextImage.show().addClass(‘activeImage’);
}
}
[/cc]
Next, we need to include the code that will fade out the existing image and fade in the new image:
[cc lang=”javascript”]
function swap($activeImage, $nextImage, shouldFade) {
if(shouldFade) {
$activeImage.fadeOut(function() {
$(this).removeClass(‘activeImage’);
$nextImage.fadeIn(function() {
$(this).addClass(‘activeImage’);
});
});
} else {
$activeImage.hide().removeClass(‘activeImage’);
$nextImage.show().addClass(‘activeImage’);
}
}
[/cc]
Save your work. The final version of your plugin should look like this:
[cc lang=”javascript”]
(function($) {
jQuery.fn.makeSlideshow = function(options) {
var opts = jQuery.extend({}, jQuery.fn.makeSlideshow.defaults, options);
return this.each(function() {
$(this).children(‘:not(:first)’).hide();
$(this).children(‘:first’).addClass(‘activeImage’);
setInterval(function() {
if($(‘.activeImage’).next().length > 0) {
swap($(‘.activeImage’), $(‘.activeImage’).next(), opts.fade);
} else {
swap($(‘.activeImage’), $(‘.activeImage’).siblings(‘:first’), opts.fade);
}
}, opts.speed);
});
};
jQuery.fn.makeSlideshow.defaults = {
fade: false,
speed: 3000
}
})(jQuery);
function swap($activeImage, $nextImage, shouldFade) {
if(shouldFade) {
$activeImage.fadeOut(function() {
$(this).removeClass(‘activeImage’);
$nextImage.fadeIn(function() {
$(this).addClass(‘activeImage’);
});
});
} else {
$activeImage.hide().removeClass(‘activeImage’);
$nextImage.show().addClass(‘activeImage’);
}
}
[/cc]
4. Trying It Out
Next, open up the MyjQueryPlugin.js file that’s in the JavaScript directory of your project. It should include the following lines of code:
[cc lang=”javascript”]
$(function() {
$(‘.my-images’).makeSlideshow();
});
[/cc]
Obviously, this passes no options to the plugin. Let’s try passing a speed option to the plugin to speed it up. Have the slideshow change images every two seconds:
[cc lang=”javascript”]
$(function() {
$(‘.my-images’).makeSlideshow({
speed: 2000
});
});
[/cc]
Refresh your page and you should notice the images displaying at a quicker speed.
Now let’s add fading into the mix:
[cc lang=”javascript”]
$(function() {
$(‘.my-images’).makeSlideshow({
speed: 2000,
fade: true
});
});
[/cc]
Once again, refresh the page and you should notice the fade effect now occurs between image transitions.
Cool, huh? As usual, you can download the complete working source of this project here.
That completes this plugin. In the final part of the series, we’ll take a look at how you can actually deploy this to the jQuery plugins repository as well as some suggestions for getting the word out about future work that you release.
chapster says
Great tutorial loved it. One question why would you make the swap method global instead of adding it to the plugin?