jQuery: The Write Less, Do More JavaScript Library

Plugins/Authoring

From jQuery JavaScript Library

Jump to: navigation, search

jQuery offers a mechanism for adding in methods and functionality, bundled as plugins. Most of the methods and functions included in the default download are written using the jQuery plugin construct.

Plugin writing comes in two steps. The first is writing any of your public methods and functions, for example:

jQuery.fn.debug = function() {
  return this.each(function(){
    alert(this);
  });
};
jQuery.log = function(message) {
  if(window.console) {
     console.debug(message);
  } else {
     alert(message);
  }
};

Coders will now be able to call your new plugin, like so:

$("div p").debug();

Or use your functions:

try {
  // do some error prone stuff
} catch(exception) {
  $.log(exception);
}

There are a few very important points to remember:

  • Name your file jquery.[insert name of plugin].js, eg. jquery.debug.js
  • All new methods are attached to the jQuery.fn object, all functions to the jQuery object.
  • inside methods, 'this' is a reference to the current jQuery object.
  • Any methods or functions you attach must have a semicolon (;) at the end - otherwise the code will break when compressed.
  • Your method must return the jQuery object, unless explicity noted otherwise.
  • You should use this.each to iterate over the current set of matched elements - it produces clean and compatible code that way.
  • Always use jQuery instead of $ inside your plugin code - that allows users to change the alias for jQuery in a single place. See below for an explanation and a more elegant solution.

If you're curious as to how a full plugin looks, feel free to browse the plugins or look through the jQuery Source Code.

The above will suffice for small and simple plugins, but in other scenarios, a more sophisticated approach is necessary.

Contents

Collecting static functions in objects

If you need multiple public static methods, you should add them to an object. Eg. if you start with this:

jQuery.logError = function() { ... };
jQuery.logWarning = function() { ... };
jQuery.logDebug = function() { ... };

Change it to:

jQuery.log = {
  error : function() { ... },
  warning : function() { ... },
  debug : function() { ... },
};

This avoids namespace cluttering and can prevent a lot of issues.

Hiding variables

There are different scenarios where you want to define your plugin methods in a loop, without specifying each one. Something like this:

var newMethods = {
  check       : function() { ... },
  uncheck     : function() { ... },
  toggleCheck : function() { ... }
};
jQuery.each(newMethods, function(i) {
  jQuery.fn[i] = this;
});

To hide the variable newMethods from other code, you should wrap the code into a function:

(function() {
  var newMethods = {
    check       : function() { ... },
    uncheck     : function() { ... },
    toggleCheck : function() { ... }
  };
  jQuery.each(newMethods, function(i) {
    jQuery.fn[i] = this;
  });
})();

Options

It is good practice to design your plugin so that it can be used without having to specify lots of parameters. To make it as flexible as possible, you should provide several options with sensible defaults. Consider a plugin that always needs a URL as a parameter, and has 'name' (string), 'size' (number) and 'global' (boolean) as optional parameters. You should code your plugin like this:

jQuery.fn.pluginName = function(url, settings) {
  // define defaults and override with options, if available
  // by extending the default settings, we don't modify the argument
  settings = jQuery.extend({
     name: "defaultName",
     size: 5,
     global: true
  }, settings);

  // do the rest of the plugin, using url and settings
}

You use the plugin without options like this:

$('selection').pluginName('mypage.php');

Or with two of three options like this:

// override defaults for name and size, but not global
var options = {
  name: "foobar",
  size: 10
}
$('selection').pluginName('mypage.php', options);


Suggested reading: Mike Alsup has written a great plugin development pattern.

Using jQuery.extend to extend jQuery itself

In the above section, we applied jQuery.extend(settings, options) to extend the plugin settings object. Now, by passing only one object argument instead of two or more, we change the intent of the jQuery.extend function to extend the jQuery object itself with the given object argument. This allows you to add stuff to nearly every aspect of jQuery, eg. new methods:

jQuery.fn.extend({
  check       : function() { ... },
  uncheck     : function() { ... },
  toggleCheck : function() { ... }
});

But you can use jQuery.extend also to extend other objects defined inside of jQuery, eg. to add new selectors:

jQuery.extend(jQuery.expr[":"], {
  text     : "a.type=='text'",
  radio    : "a.type=='radio'",
  checkbox : "a.type=='checkbox'",
});

Customizing animations

Your plugin may use an animation for certain events, e.g. the tabs plugin can use fade or slide animations when the tab is changed. Making the animations customizable is quite easy when using the animate method (see the API documentation for details). The following example uses a fade as default:

jQuery.fn.foobar = function(settings) {
  settings = jQuery.extend({
    animation: {opacity: "hide"}
  }, settings);
  // use the animation setting as a parameter for animate
  jQuery(...).animate(settings.animation);
}

By passing a hash for the animation option, you could use a slide:

jQuery(...).foobar({
  animation: {height: "hide"}
});

Custom Alias

It was stated above that you should not use the "$" alias inside your plugin code. This allows users of jQuery and your plugins to change the alias from "$" to something else like "jQ". That is necessary when working with other libraries or frameworks which make use of the "$" alias.

Still, $ is a very handy shortcut, and instead of not using it, we should not rely on its existence. Instead, we can simply define our own alias (and call it "$") for our code.

Custom Alias in plugin code

The trick is to define all plugin code inside a function and execute this function immediately. The construct looks like this:

(function() {
  // put plugin code here
  var xyz; // xyz is NOT a global variable, it is only visible inside this function
})(); // execute the function immediately!

The additional parentheses are necessary! You can't execute an anonymous function without them.

Ok, now to the fun part:

(function($) {
  // plugin code here, use $ as much as you like
})(jQuery);

We pass "jQuery" to the function and can now use whatever alias for jQuery we like. So instead of "$" you could also use any other valid JavaScript variable name.

See the tooltip plugin for a plugin that uses this construct.

Custom Alias in page code

When writing jQuery code for the examples that illustrate the use of your plugin, you may want to consider using an alias technique to make your code more forward-compatible. Many examples of jQuery code (including examples distributed with many plugins) are written using the $ alias. This can be a problem for people using your plugin by starting to copy the example code if their web pages already use the $ alias for another purpose.

To prevent this, you can nest your example code in the DOM ready event handler, which is shown below in its shorthand form. The first argument to your function can be the $ alias, which you can then use as your jQuery alias throughout the code inside the function.

 jQuery(function($) {
   // your code using $ alias here
 });

That way, you type jQuery only once and can use the alias safely inside the ready handler code. For more information, including caveats about this technique, see Using jQuery with Other Libraries.