Creating Our First jQuery Plugin

Exclusive offer: get 50% off this eBook here
jQuery Plugin Development Beginner's Guide

jQuery Plugin Development Beginner's Guide — Save 50%

Build powerful, interactive plugins to implement jQuery in the best way possible

$26.99    $13.50
by Giulio Bai | October 2010 | Beginner's Guides Open Source Web Development

As the name suggests, this article by Giulio Bai, author of jQuery Plugin Development Beginner's Guide, is about creating our first, working, and fantastic jQuery plugin! This article deals with the correct creation of a plugin of any sort, the basic outline of a plugin and what is fundamental for successfully developing a plugin from scratch. Step-by-step instructions are provided in order to guide even very beginners to the successful realization of their first plugin.

This article will be about the following topics:

  • Defining our own default plugin structure
  • Setting the basics for our first plugin
  • Getting a step farther
  • Dealing with options
  • Using functions inside the plugin
  • Closures: making functions private

 

jQuery Plugin Development Beginner's Guide

jQuery Plugin Development Beginner's Guide

A practical straightforward guide for creating your first jQuery plugin

  • Utilize jQuery's plugin framework to create a wide range of useful jQuery plugins from scratch
  • Understand development patterns and best practices and move up the ladder to master plugin development
  • Discover the ins and outs of some of the most popular jQuery plugins in action
  • A Beginner's Guide packed with examples and step-by-step instructions to quickly get your hands dirty in developing high quality jQuery plugins
        Read more about this book      

(For more resources on jQuery, see here.)

Defining our own default plugin structure

To make things easier to remember and apply, we are going to start off with the definition of what we will be referring to when speaking of the basic template that all the plugins we are going to develop should conform to.

Actually, we have already had a quick look at it earlier in the previous chapter, but there's something more definitely worth saying.

From now on, we will call the following code the default structure for our plugins. This is what we will promptly copy and paste into each file we're going to write a plugin into.

jQuery.fn.PLUGINNAME = function() {
return this.each(function() {
// code
});
}

Needless to say, the this.each loop iterates all of the matching elements. We return the jQuery object (this) to allow chaining. We extend the jQuery.fn object; all of the code will be put inside the function.

Also:

  • The file name of every plugin we're going to develop will be
    jquery.PLUGINNAME.js.

    For the moment, remember to always avoid referring to the jQuery object with the dollar sign ($), to prevent possible conflicts with other libraries. We'll get to using aliases very soon.

  • All of the functions that we write to make our plugin work should be private and not accessible from outside, in an attempt to avoid cluttering and possible backwards incompatibility.
  • If not from the very start, at least at the end, a user will be able to specify options to control the plugin behavior.
  • Default options for the plugin will be publicly accessible to allow for easier customization with minimal code.

The directory that the plugin resides in will also contain two other files, by default:

  • index.html: This is our test page.
  • jquery.js: This is the jQuery library that we need to make things work.

Setting the basics for our first plugin

As our first plugin, we might want to create something uncomplicated but somewhat impressive: what about something that, when the cursor is hovering over an element, substitutes the text contained with some words of our choice?

Time for action – our first plugin, Part I

Getting started in creating jQuery plugins in not difficult at all. For example, creating this simple plugin should help us in understanding how things actually work.

  1. Given that our plugin name is txtHover, create all the directories and files we need by default, and copy over the jquery.js file.

    Creating Our First jQuery Plugin

  2. Copy the default structure for our plugins to the plugin file and make sure the function is named accordingly. It should look like this:

    jQuery.fn.txtHover = function() {
    return this.each(function() {
    // code
    });
    };

  3. Nothing's easier to do than change the text contained in some element. Inside the plugin function, write the following to let the trick happen:

    jQuery(this).text("Text changed");

  4. To test this in action, we can modify the HTML document to look like this:

    <!DOCTYPE html>
    <html>
    <head>
    <script src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="jquery.js"></script>
    <script src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="jquery.txthover.js"></script>
    <script>
    $(document).ready(function() {
    $("p#one").txtHover();
    });
    </script>
    </head>
    <body>
    <p id="one">Some text.</p>
    </body>
    </html>

  5. Unfortunately, the result is neither fancy nor satisfactory—something we've experienced earlier too. But we're just getting started; we won't stop here this time!

    Creating Our First jQuery Plugin

What just happened?

The plugin is working correctly so far. When the page loads, the text is changed to what we had defined into the plugin code.

However, there are a couple of things to pay attention to:

  • The function text() from the jQuery API expects either one or no arguments to be passed: if there is no argument the function returns the current content of the selected element. The text string passed as an argument substitutes the element text otherwise.

    There are, however, some similarities with the html() function, which treats the text it operates on as if it were HTML code. That is, passing any tag to the html() function results in having the element possibly containing other elements after the operation (also, the same applies for getting HTML code from within the element), whereas the this function will just treat the HTML code as plain text and not affect any element hierarchy.

  • The fact that the text cannot be changed, unless we directly modify the code of the plugin.

Getting a step farther

Despite the good realization, our plugin still misses the point. Our goal was to activate the text substitution whenever the mouse pointer hovered over the text to be replaced, whereas our current implementation does it right after the page is loaded.

We put it inside the "document ready" statement, after all!

Time for action – our first plugin, Part II: Hovering

By adding little pieces of code one at a time, we can easily understand what we are going to do and which is the best layout for our plugin. Activating the plugin whenever the mouse pointer hovers over the selected elements is surely another little step that adds up to reach our final goal.

  1. Back to our plugin file, we have to change the code so that the whole mechanism activates when the hover event is triggered. jQuery provides a function called hover(), which we can use to achieve our objective:

    jQuery.fn.txtHover = function() {
    return this.each(function() {
    jQuery(this).hover(function() {
    jQuery(this).text("Mouse hovered");
    });
    });
    };

  2. Now, on to testing. Once the mouse pointer hovers over the text, it is effectively replaced by our string. But even if the mouse is moved, the text doesn't revert to the original.

    Creating Our First jQuery Plugin

  3. In fact, looking at the hover documentation, we see the function can also take a second argument, that is, the pointer to a function to be executed when the mouse goes off the element.

    Our modified code will now look like the following:

    jQuery.fn.txtHover = function() {
    return this.each(function() {
    var oldTxt = jQuery(this).text();

    jQuery(this).hover(function() {
    jQuery(this).text("Mouse hover");
    }, function() {
    jQuery(this).text(oldTxt);
    });
    });
    };

  4. The result is somewhat better now: the text is changed when we leave the pointer on the paragraph, and is changed again to its original form once the pointer is moved away.

What just happened?

We might be a little more satisfied with this evolution of our plugin, even though it's far from complete.

Its functioning is fairly straightforward: we have made use of a variable (oldTxt) to store the old content, and we then have proceeded to using two anonymous functions (function(){ }), passed as arguments to the hover() function, to handle the mouse hover event (write our string) and the mouse out event (text back to original).

There's still something to do though:

  • We have used far too many instances of $(this) in our code and, on a larger scale application, a lot of memory would be wasted this way. It will be incredibly better for performance to make up a variable and use it every time we refer to the element with $(this).
  • The text cannot be changed, unless we directly modify the code of the plugin.

Have a go hero – html () versus text ()

Read the documentation for the html() function.

Create a plugin that, once the mouse pointer hovers over an element, displays the HTML code of its content. The content should then change back to normal once the mouse pointer is moved away from that space.

What happens if the html() and text() functions are used one inside the other, that is, $(sel).text($(sel).html()) or $(sel).html($(sel).text())? Just play around a little bit.

jQuery Plugin Development Beginner's Guide Build powerful, interactive plugins to implement jQuery in the best way possible
Published: October 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on jQuery, see here.)

Dealing with options

An aspect that we left out in the creation of our plugin is the one concerning options and, thus, customization.

Implementing options not only will drastically increase the flexibility and ease of customization of the plugin, but will also quicken later modifications by the author himself or herself, as it results in the whole code being simpler to understand and the important bits would be all grouped together.

Time for action – our first plugin, Part III: Options

To allow for options to be specified and the behavior of our plugin to be customized and modified to users' liking, we need options.

  1. The code we use for our plugin will be modified to look like the following:

    jQuery.fn.txtHover = function(options) {
    var defaults = {
    txt: 'Mouse hover'
    };

    var o = jQuery.extend(defaults, options);

    return this.each(function() {
    var e = jQuery(this);
    var oldTxt = e.text();
    e.hover(function() {
    e.text(o.txt);
    }, function() {
    e.text(oldTxt);
    });
    });
    };

  2. We are allowed to change the txt option now. In case we don't, though, the default value will be used (Mouse hover).

    The document ready statement should now contain the following:

    $(document).ready(function() {
    $("p#one").txtHover({ txt: 'This is some custom text.' });
    });

  3. And the result would look something like this, with the text changed to whatever we like:

    Creating Our First jQuery Plugin

What just happened?

The structure we've just used to get our plugin packed with options is quite flexible and easily extensible.

We first made sure the function definition would include an argument (that is, options) for settings to be specified. The options object must be formatted following the inline object creation method (that is, { option1: value1, option2: value2 } and so on).

But what would happen if the user does not specify any options? Or, if we are dealing with a number of options, wouldn't writing the same lines of code everytime to reset option values be incredibly annoying?

Instead, we create a new (plain) object (default) in which we store the default values of options we plan on accepting as valid. This way, users may check if the default value is acceptable to them and either leave it untouched (the plugin will then use the default value) or change it to their needs, resulting in the plugin making use of the customized value for that particular option.

The very next line is the way jQuery is instructed to combine the two objects. If any of the options we are going to make use of later on in the code (and want the user to be able to modify) is not passed to the function, we use the default one instead.

What we'll get at the end is another object (o) with the values we need for the plugin to work with. From this moment onwards, we'll use this object's values to access options we need during development.

The rest of the code is left untouched, except for the o.txt part that replaces the old string. Users are now able to choose what they want to replace the original content with.

Also, the keyword $(this), much abused of in the previous version, has been replaced with the variable e, into which all of the information of the element has been copied. In a large-scale environment, this little tweak will result in a huge boost to the script performance.

Have a go hero – adding colors

Accessing and modifying an element's CSS properties through the css() method is not only possible, but quite simple and straightforward too.

The css() method works very much like the text() and html() ones do, with the difference being that it always expects at least one argument to be passed, as the first parameter is responsible for selecting which property we want to get access to.

Using your knowledge about the above-mentioned method and what you've just learned from the latest Time for action, extend the plugin so it accepts two other options: fgColor and bgColor.

Needless to say, these two options make the users able to change the element's background and foreground color whenever the mouse pointer hovers over the element. When the mouse pointer gets off the area, colors should revert to original.

Keep in mind that, if either of those two options is not passed, the user does not intend to have the color(s) changed at all and they should appear as they already are, not just as black text on white background!

Using functions inside the plugin

Repetitive tasks are boring. And this is the reason functions exist. However, how do functions interact with the code of a plugin?

Very simply, every function declared outside the plugin's own code (note that defining a function right inside it is allowed) is accessible as it would be in any other piece of code.

Time for action – our first plugin, Part IV: Functions

For testing reasons only, we need a debug function to tell us what happens at certain points when the code runs. This will also help us in understanding when and how functions are accessible from a particular portion of code.

  1. We could add the following function (from our previous log script) at the very beginning of the plugin file:

    function _debug(msg)
    {
    if(window.console) {
    console.debug(msg);
    } else {
    alert(msg);
    }
    }

    jQuery.fn.txtHover = function(options) {
    // the rest of the code
    // goes here
    };

  2. Our plugin would then read (with the addition of some debug facilities):

    function _debug(msg)
    {
    if(window.console) {
    console.debug(msg);
    } else {
    alert(msg);
    }
    }

    jQuery.fn.txtHover = function(options) {
    var defaults = {
    txt: 'Mouse hover'
    };

    var o = jQuery.extend(defaults, options);

    return this.each (function() {
    var e = jQuery(this);
    var oldTxt = e.text();

    e.hover(function() {
    _debug ("Mouse hovers #" + e.attr('id')
    + " (\"" + o.txt + "\")");
    e.text(o.txt);
    }, function() {
    _debug("Mouse leaves #" + e.attr('id'));
    e.text(oldTxt);
    });
    });
    };

    Creating Our First jQuery Plugin

  3. There's still some trouble, though: what happens if we use the debug function outside the plugin file?

    We expect it not to be accessible or to be somehow unusable, as we have declared it inside the plugin file and it was intended for use inside the plugin only.

    If we try to put a sample call right after the "document ready" statement, we can see the function to be actually accessible from everywhere in the code.

    $(document).ready(function() {
    _debug("Hello, this is a test call.");
    $("p#one").txtHover({ txt: 'This is some custom text.' });
    });

    Creating Our First jQuery Plugin

What just happened?

Dealing with functions shouldn't be much of a problem. We are supposed to be used to making heavy use of them.

However, the point is their accessibility from different parts of the code. At first, we create the function(s) we need without thinking about the number of problems that could arise if we do not protect them and struggle to make the functions we use in our plugin private (that is, not accessible from outside our plugin).

What we must be aware of are the issues we could bump into when defining a certain function in our plugin file without thinking that the very same name we originally thought would have been unique (for example, _debug) has been used somewhere else in the code to name a function whose goal is completely different.

The correct (or, at least, expected) behavior of our plugin is compromised and for no reason should we permit such a stupid error.

Another point of particular interest, in case it's not been noticed before, is the way the o object is used everywhere at any point of time that we need to refer to the current set of options, whereas e is the current element being processed.

Have a go hero – experimenting with functions

Play around with functions. Try to define some functions nearly everywhere it is possible and try calling them from other parts of the code to see what happens, which functions override which, and the difference between calls to functions with one or more arguments.

Also, make sure you notice where (that is, in what parts of code) a function can be defined and where, instead, it's not possible.

Is it possible to define a function inside the document ready statement? If so, what would it mean and is there any advantage?

jQuery Plugin Development Beginner's Guide Build powerful, interactive plugins to implement jQuery in the best way possible
Published: October 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on jQuery, see here.)

Closures: Making functions private

With the aim of keeping our own functions, those needed by our plugin only, private, so that others cannot access and misuse them, we're going on to discovering closures.

Time for action – our first plugin, Part V: Closures

Closures make it possible for the developer (that is, us) to avoid creating functions in the main namespace and keep them private to avoid problems with naming, backward compatibility issues, and excessive cluttering.

  1. We're now going to add a function to the index.html file, called _debug.

    This new function will take one argument (just like our plugin's one) and will do nothing more than just display an alert reporting some random text.

    function _debug(argument)
    {
    // Note we don't make use of the 'argument'
    // we just need it for the function to look
    // exactly the same as our plugin's debug function
    alert("Hi, this is the fake debug function.");
    }

    $(document).ready(function() {
    _debug("Hello, this is a test call.");
    $("p#one").txtHover({ txt: 'This is some custom text.' });
    });

  2. Now, on loading the page, how does the result appear? Is it what you expected? The newly created function completely replaced our plugin's function, making the behavior definitely not the same.

    Creating Our First jQuery Plugin

  3. What would happen if we use closures to prevent this type of inconvenience from happening?

    Here is how closures work. This is how the plugin code should look now:

    (function($) {
    function _debug(msg)
    {
    if(window.console) {
    console.debug(msg);
    } else {
    alert (msg);
    }
    };

    jQuery.fn.txtHover = function(options) {
    var defaults = {
    txt: 'Mouse hover'
    };

    var o = jQuery.extend(defaults, options);

    return this.each(function() {
    var e = jQuery(this);
    var oldTxt = e.text();

    e.hover(function() {
    _debug("Mouse hovers #" + e.attr('id')
    + " (\"" + o.txt + "\")");
    e.text(o.txt);
    }, function() {
    _debug("Mouse leaves #" + e.attr('id'));
    e.text(oldTxt);
    });
    });
    };
    })(jQuery)

  4. And here is how the page looks now, after we have modified the plugin code. When the page loads, we get to see the pop up:

    Creating Our First jQuery Plugin

    But when we hover the mouse pointer over the text we actually see what we expected to see:

    Creating Our First jQuery Plugin

What just happened?

Using closures is definitely a best practice that everyone should follow.

Not only does it allow functions to be defined for the plugin only (keeping them private and not accessible from outside the plugin's code), but many other advantages come as well.

The way in which closures operate is quite simple after all. By creating a closure, several things actually happen: first of all, closures create a function with $ as its parameter.

Then that function is immediately called with the value jQuery, which gets mapped onto the $, letting us use the $ sign without the fear of creating any kind of issue.

When we first defined the fake debug function, we probably didn't think it would've overwritten the whole content of the plugin's original function. Perhaps it would've given an error; or just the first call (the one right before the plugin call) would've been compromised.

Actually, this behavior is perfectly explainable. Looking at the file structure, we see the jquery.js file is included first, then comes the plugin, and finally the inline script part containing the fake function and the "document ready" statement.

This means the latest part quite naturally overwrites the earlier ones.

Thus, having defined the fake debug function at the very end, it obviously overwrites the old debug function coming before it.

The whole example would have been quite different if we had put the above-mentioned function before the inclusion of the plugin file, in which case the dynamics would have been worthy of notice.

In the latest version, the original debug function is kept private and thus the fake function cannot overwrite it, resulting in the correct behavior that we would've expected from the very beginning. As the page loads, a pop up is displayed with some text, whereas the hovering effect still works correctly thanks to closures preventing the functions declared inside them from being publicly visible.

Have a go hero – avoid conflicts

With closures in mind, try to replace all the jQuery words with the dollar sign, as if you where using normal jQuery syntax in a normal script.

If you even try to throw in some conflicts over the dollar sign, which is often used by other libraries as well (for example, by including another JavaScript library and using both to get something done), you can see the plugin still works correctly.

In fact, apart from keeping functions to themselves, this closure alias the word jQuery to the symbol $, acting as the noConflict() function would on the plugin code.

This is particularly handy because it allows the normal syntax, the one we're all most used to and that comes out without thinking, to be used with no worries at all.

Summary

This article has covered, step by step, the creation of a simple plugin. At the very beginning, the plugin was really simple and far from being well thought out. However, by the end of the process we ended up with a simple plugin, capable of doing several things, and a structure evolving constantly after each step.

Perhaps without having noticed, we've taken care of event handling (for example, the hovering effect, with its hover and leave events), customization, modification, user personalization (making a set of options available and thinking about the default values), security, compatibility issues, and aliasing (making the plugin work within closures and having the possibility to use the dollar sign ($) again).


Further resources on this subject:


About the Author :


Giulio Bai

Giulio Bai is a law student living in Italy who spends most of his time toying with stuff that doesn't have anything to do with law.

Even after trying to keep the list of his past achievements as short as possible, the number of projects that he joined in (and that invariably sunk shortly thereafter) makes it hard to narrow down his interests to programming and carousels alone.

It should be made clear that any claim of responsibility for those unfortunate ventures is wholeheartedly rejected – they never had the necessary potential to make it anyway.

Books From Packt


jQuery 1.4 Reference Guide
jQuery 1.4 Reference Guide

jQuery UI 1.7: The User Interface Library for jQuery
jQuery UI 1.7: The User Interface Library for jQuery

CMS Design Using PHP and jQuery
CMS Design Using PHP and jQuery

Learning jQuery 1.3
Learning jQuery 1.3

Joomla! 1.5 JavaScript jQuery
Joomla! 1.5 JavaScript jQuery

WordPress 3.0 jQuery
WordPress 3.0 jQuery

Drupal 6 JavaScript and jQuery
Drupal 6 JavaScript and jQuery

PHP jQuery Cookbook
PHP jQuery Cookbook


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software