Understanding jQuery Plugins

If you’re here, I’m sure it’s no surprise jQuery is an easy library to use. jQuery may be easy, but it still has its quirks and can be difficult for some to grasp beyond basic functionality and concepts. No worries, I’ve got a simple guide here to help break down code, that may seem like overly complex syntax, into simple thoughts and patterns that can be easily understood.

  1. The Container: An Immediate Function
  2. The Plugin: A Function
  3. Multiple Elements: Understanding Sizzle
  4. Functionality: Public & Private Methods
  5. Plugin Settings: Passing Arguments
  6. Retaining Settings: Adding Persistant Data

Here, we’ve got a basic plugin layout:

You may notice the structure I’ve provided is significantly different from others. Plugins can vary depending on usage and needs. Here, it is my goal to explain the concepts in code well enough for you to understand and author a plugin in such a way that suits you best.

1. The Container: An Immediate Function

Essentially every plugin is contained in an immediate function like so:

An immediate function is, as its name insinuates, a function. What’s unique about it is it’s enclosure in parenthesis, this makes everything inside the function run within a local scope. This does not mean the DOM (global) is protected, but rather all public variables and object namespaces are inaccessible. This makes a perfect start for defining variables and objects to your hearts content without interfering with existing code.

Now since all public variables are inaccessible, that could be a problem seeing jQuery itself is, in fact, a public variable. Just like any function, immediate functions can be passed variables and objects are passed by reference. We can just pass jQuery into our immediate function like so:

So what I’m doing here is passing jQuery as a public variable into the immediate function where I can reference it locally (inside the container) as $. In other words I’m calling the container as a function and passing jQuery as an argument. This also allows for compatibility with Prototype, since the public variable I am referencing is jQuery rather than it’s short code $. If you don’t use Prototype or any other library using $ as a short code it isn’t as relevant but still good to know.

2.The Plugin: A Function

Every jQuery plugin is essentially a large function we shove into the jQuery namespace, while we can easily assign our function using jQuery.pluginName = function, but if we do so our plugin’s code isn’t protected. jQuery.fn is a short code to jQuery.prototype, meaning it can only be read (and not modified) when using the jQuery namespace to access it. What purpose does this actually serve you? Not much other than writing your code properly and understanding protecting your code from unwanted runtime modification. Best said, it’s just good practice!

We’ve got a basic jQuery function via a plugin:

The above code function can be run just like any other jQuery function using $(‘#element’).pluginName(). Notice how I include return this; this small piece of code allows chain-ability by returning the original elements (contained in this) wrapped in a jQuery object. You should also note that this within this particular scope is a jQuery object, the equivalence of $(‘#element’).

This could be summarised by stating the object returned, in the code above, by $(‘#element’).pluginName() is exactly the same as $(‘#element’), and within your function’s immediate scope there is no need to wrap this into a jQuery object such as $(this) as it has already been done.

3. Multiple Elements: Understanding Sizzle

jQuery uses a selector engine called Sizzle, which supports selecting multiple elements (such as entire classes) for use with functions. This is one of the great features of jQuery, but it’s also something to be considered when developing a plugin. Even if you don’t anticipate grabbing multiple elements with your plugin, it’s still good practice to plan for such in the event.

Here I’ve added in a few pieces of code to account for and run code on multiple elements, individually:

In this example, I’m not using each() to run code over each element I have in the selector. Within the function called by each() the individual element being processed can be referenced in the local scope by this and used as a jQuery object by $(this). It’s also good practice to store the jQuery object you with to manipulate rather than calling $(this) each time you wish to run a function. Doing such is, of course, optional and not always needed; I have included it for good measure. Also note that we will be moving the each() command into our individual functions, this way we can return values when calling methods.

One example of this would be a plugin that supports a val method for returning a value:

4. Functionality: Public & Private Methods

A basic function may work for some cases, but more complex plugins will require a various supply of methods and private functions. You may be tempted to use various namespaces to provide various methods for you plugin, but it’s best not to clutter your sources with excess namespaces.

The code snippet below defines a JSON object to store public methods and demonstrates how you can use your plugin’s primary function to determine which method needs calling and call that method on each element in the selector.

Notice how I have placed privateFunction as a global. This is more than acceptable considering all is within the plugin’s container, therefore it’s only accessible to the scope of the plugin. In the plugin’s main function, I am checking if a method to be passed exists. If a method does not exist or the argument passed is an object, the init method is run. Lastly, if the argument passed is not an object and a method doesn’t exist, we send out an error.

Also note how each method I am using this.each(). When I am calling method.call(this) in the main function, this is in fact a jQuery object and is being passed into each method as this. So within our methods’ immediate scope it is already a jQuery object. Only in our function being called by each() do we need to contain this in a jQuery object.

Here are some usage examples:

The above examples do show {}, which would represent arguments. While it will still work with the code in this section, the arguments will not be passed. Proceed to the next section for passing arguments.

5. Plugin Settings: Passing Arguments

Many plugins support passing parameters such as configurations and callbacks. You can pass information either by function arguments or by a JS object using key-value pairs. If your plugin supports more than one or two parameters, it’s best practice to pass parameters in an object.

As seen above, an options argument has been added to the functions and arguments also added to the main function. If a method has been declared, that method is also removed from the arguments before passing them to the method. I have swapped call() for apply(); apply() essentially does the same as call(), with support for passing arguments. This structure also supports more than one argument, if you wish to use such instead, just modify the arguments for you methods. e.g. init: function(arg1, arg2) {}

If using a JS object for parameters, you may want to define a defaults variable. Once a defaults variable has been declared, you want to use $.extend to merge values into a final parameter object (in this case, settings) for use.

To demonstrate, here are a few examples of logic:

6. Retaining Settings: Adding Persistant Data

Sometimes you’ll want to retain settings and information within your plugin, to do such the jQuery data() function can be used. It’s quite simple in practice, make an attempt to fetch data associated with the element and if such data doesn’t exist, create it and add it to the element. Once you add information using data(), make sure to keep in mind deallocating resources when no longer needed using “removeData()”.

In the code above, I am checking if data for the elements exists. If data for the element doesn’t exist, settings are created by merging the the passed options and defaults, then saved using the data() command.


Leave a Reply

Your email address will not be published. Required fields are marked *