This section contains a set of guidelines to help you to name and structure a plugin. These guidelines ensure not only that your code plugs into the jQuery architecture properly, but also that it’ll work and play well with other jQuery plugins and even other JavaScript libraries. Here we’ll outline the basics and the best practices to follow when authoring a plugin.
Extending jQuery takes one of two forms:
- Methods to operate on a jQuery collection (what we’ve been calling jQuery methods)
- Utility functions defined directly on $ (the alias for jQuery)
In the remainder of this section, we’ll go over some guidelines that are common to both and then we’ll dedicate other sections to each specific type.
To help you with the learning process, as you discover more rules to follow you’ll also put them into action. The goal is to build Jqia Context Menu (Jqia being short for jQuery in Action), a jQuery plugin to show a custom context menu on one or more specified elements of a page. The context menu is the one that’s shown on a PC screen when you click the right mouse button on a page or press the menu key on the page when it’s focused.
For the context menu, the plugin will use an element of the page (typically a list), hidden by default, that has to be set up in the page. The element of the page acting as the menu will be retrieved through its ID. Your plugin will allow two actions, so it’ll have two methods: one to initialize the plugin and one to destroy the effect. When initialized, the plugin will override the default behavior of the right click (which shows the usual context menu) to display the custom menu. When performing the destroy action, the plugin will clean up the resources and restore the default behavior.
Finally, to make things even more interesting, you’ll enable developers who use your plugin to override the left click too. In this case, regardless of the mouse button clicked, the custom menu will be displayed. By default, this option will be disabled.
Now that we’ve explained our plan, roll up your sleeves because you have a lot of work to do.
File- and function-naming conventions
The first decision to make when developing a plugin is its name. When naming a plugin, you must avoid name collisions. It’s important that the plugin you develop doesn’t conflict with other files or plugins, which would lead to big headaches for web page authors.
The guideline recommended by the jQuery team is simple but effective, advocating the following format:
- Choose a name for the plugin that’s short but also reasonably descriptive.
- Prefix the filename with jquery.
- Optionally add the name of the company or the suite.
- Follow that with the name of the plugin.
- Optionally include the version number of the plugin.
- Conclude with .js.
Taking our Jqia Context Menu plugin as an example, if you want to follow all these recommendations, you should name the file jquery.jqia.contextMenu-1.0.0.js.
The use of the jquery prefix eliminates (ideally) any possible name collisions with files intended for use with other libraries. After all, anyone writing non-jQuery plugins has no business using the jquery prefix, but that leaves the plugin name itself still open for contention within the jQuery community. In our example, the name of the plugin consists of more than a word (at this point a lot of names are already taken). We wrote the words using camel-case syntax, but you can use lowercase for all the words or even separate them by dots or dashes. Which one you use is a matter of personal taste, and our suggestion is to pick a convention and stick with it.
One way to ensure that your plugin filenames are unlikely (you can never be 100% sure) to conflict with others is to subprefix them with a name that’s unique to you or your organization or a suite. For example, if we wanted to subprefix plugins that belong to this app, we could use the filename prefix jquery.jqia, as you did in the previous example.
The third point of the list is optional for a good reason. Let’s say that some developers are using a plugin we’ve published. Things are going nice and our plugin is successful. We want to ship a new version having new features, and here comes the problem. Our file is called something like jquery.jqia.contextMenu-1.1.0.js. Thus, the developers using our plugin not only have to update the JavaScript file but also have to change the markup to update the version suffix. It would have been much simpler if our plugin file was called jquery.jqia.contextMenu.js, specifying the version with a comment inside the file. Doing so, the developers could have replaced only the JavaScript file without updating the markup.
These explanations should clarify why you need such rules. You can put them into action with your plugin project. You’ll ignore the optional rule about the version, so go on and create a new file, naming it jquery.jqia.contextMenu.js.
In this section we stressed the importance of naming files and how you can’t make any assumption about what’s been used in other developers’ websites. The same concern applies to our lovely $ shortcut. Let’s dig in.
Beware the $
Having written a fair amount of jQuery code, we’ve seen how handy it is to use the $ alias in place of jQuery. But when writing plugins that may end up in other people’s pages, we can’t be quite so cavalier. As plugin authors, we have no way of knowing whether a web developer intends to use the $.noConflict() function (discussed in section 9.2) to allow the $ alias to be used by another library (most notably Prototype). We could employ the jQuery name in place of the $ alias, but dang it, we like using $.
In section 9.2 we introduced a design pattern called IIFE (Immediately-Invoked Function Expression), covered in more details in the appendix, which is often used to make sure that the $ alias refers to the jQuery name in a localized manner, without affecting the remainder of the page. This pattern can and should also be employed when defining jQuery plugins, as follows:
(function($){
//
// Plugin definition goes here
//
})(jQuery);
By passing jQuery to a function that defines the parameter as $, the latter is guaranteed to reference jQuery within the body of the function. You can now happily use $ to your heart’s content in the definition of the plugin.
With this new wisdom in mind, open the jquery.jqia.contextMenu.js file and put the previous snippet inside it (you can omit the comments if you want).
Now take a look at another guideline for authoring plugins that deal with parameters.
Taming complex parameter lists
Most plugins tend to be simple affairs that require few, if any, parameters. Intelligent defaults are supplied when optional parameters are omitted, and parameter order can even take on a different meaning when some optional parameters are omitted.
jQuery’s on() method is a good example of such behavior; if the optional data parameter is omitted, the listener function, which is normally specified as the fourth parameter, can be supplied as the third. If the selector parameter is missing, too, you can even pass the handler as the second argument. The dynamic nature of JavaScript allows you to write such flexible code, but this sort of thing can start to break down and get complex (for both web developers and plugin authors) when the number of parameters grows larger. The possibility of a breakdown increases when many of the parameters are optional.
Consider a function whose signature is as follows:
function complex(p1, p2, p3, p4, p5, p6, p7) {
// Code here...
}
This function defines seven parameters. Now let’s say that all but the first are optional. There are too many optional parameters to make any intelligent guess about the intention of the caller when optional parameters are omitted. If a caller of this function is omitting only trailing parameters, this isn’t much of a problem, because the optional trailing arguments can be detected as undefined. But what if the caller wants to specify p7 but allow p2 through p6 by default? And what if some of the omitted parameters accept the same data type (nullifying any chance to resort to the data type of the values passed)? Callers would need to use placeholders for any omitted parameters and write
complex(valueA, null, null, null, null, null, valueB);
Yuck! Even worse is a call such as
complex(valueA, null, valueC, valueD, null, null, valueB);
Web developers using this function are forced to carefully keep track of counting nulls and the order of the parameters; plus, the code is difficult to read and understand. But short of not allowing the caller so many options, what can you do?
Again, the flexible nature of JavaScript comes to the rescue. A pattern that allows you to tame this chaos has arisen among the page-authoring communities—the options hash. Using this pattern, optional parameters are gathered into a single parameter in the guise of a JavaScript Object instance, whose property name-value pairs serve as the optional parameters.
Using this technique, our first example could be written as
complex(valueA, {p7: valueB});
The second would be as follows:
complex(valueA, {
p3: valueC,
p4: valueD,
p7: valueB
});
Much, much better!
You don’t have to account for omitted parameters with placeholder nulls, and you also don’t need to count parameters. Each optional parameter is conveniently labeled so that it’s clear exactly what it represents (when you use better parameter names than p1 through p7, that is).
Note
Some APIs follow this convention of bundling optional parameters into a single options parameter (leaving required parameters as standalone parameters). Others bundle the complete set of parameters, required and optional alike, into a single object. We prefer to use the second approach because the amount of required parameters may increase over the time, so this solution is more future-proof.
Although this is obviously a great advantage to the caller of your complex functions, what about the ramifications for you as the plugin author? As it turns out, you’ve already seen a jQuery-supplied mechanism that makes it easy for you to gather these optional parameters together and merge them with default values. Let’s reconsider our example function with a required parameter and six optional parameters. The new, simplified signature is
complex(p1, options)
Within this function, you can merge those options with default values with the handy $.extend() utility function. Consider the following:
function complex(p1, options) {
var settings = $.extend({
p2: defaultValue1,
p3: defaultValue2,
p4: defaultValue3,
p5: defaultValue4,
p6: defaultValue5,
p7: defaultValue6
},
options || {}
);
// Remainder of the function...
}
By merging the values passed by the web developer in the options parameter with an object containing all the available options with their default values, the settings variable ends up with the default values superseded by any explicit values specified by the web developer.
Tip
Rather than creating a new settings variable, you could use the options reference itself to accumulate the values. That would cut down on one reference on the stack, but let’s stay on the side of clarity for the moment.
In the previous code you guard against an options object that’s null or undefined with || {}, which supplies an empty object if options evaluates to false (as you know null and undefined do). Easy, versatile, and caller-friendly!
Now that you’ve moved another step forward in the process of learning how to create beautiful and well-written plugins, let’s apply it to your project. Recalling the description of Jqia Context Menu, you’ll remember that you need an optional parameter that specifies whether the custom menu must also be displayed when the left mouse button is clicked. In addition to this option, you need to specify the ID of the element that will act as the menu. Although you need only two parameters, one mandatory and one optional, you’ll use the approach of passing a single object to your plugin. The reason, as we mentioned before, is that this approach is more future-proof.
Turning this description into code, which must replace the contents of the JavaScript file you’re working on, results in the following:
(function($) {
var defaults = {
idMenu: null,
bindLeftClick: false
};
})(jQuery);
In this code you define an object, called defaults, containing a property to specify the ID of the menu (idMenu) and another one to know if the click with the left button should be overwritten (bindLeftClick).
At the moment you’ve only defined an object with two properties, so there’s nothing special here. Let’s move on to the guidelines regarding how you should develop the methods of your plugin.
Keep one namespace
Similarly to what you’ve seen in regard to naming files, you should ensure the names you give to your functions, whether they’re new utility functions or methods for the jQuery collections, don’t collide with methods of other extensions you might be using.
When creating plugins for your own use, you’re usually aware of what other components you’ll use; unless your project is huge, it’s an easy matter to avoid any naming collisions. What if you’re creating your plugins for public consumption? What if your plugins, which you initially intended to use privately, turn out to be so useful that you want to share them with the rest of the community?
To better understand this concept, let’s see a concrete example. As we said, Jqia Context Menu needs two methods: init() and destroy(). You might be tempted to add the following code in your JavaScript file:
var init = function(options) {
// Code here...
};
var destroy = function() {
// Code here...
};
Unfortunately this isn’t what you really need.
One of the main points of using an IIFE is to create an environment where variables and functions declared inside the IIFE can’t be accessed from outside. This behavior is indeed useful for your defaults variable that you don’t want to be visible from outside your plugin but not for your methods. Inside your IIFE you need a way to expose your methods to the outside world.
The plugin you’re creating operates on jQuery collections, and to add a method for jQuery collections you must assign them to a property named $.fn. Updating your JavaScript file to comply with these considerations results in the code shown in the following listing.
Listing 12.1. A first version of the Jqia Context Menu plugin
(function($) {
var defaults = {
idMenu: null,
bindLeftClick: false
};
$.fn.init = function() {
// Code here...
};
$.fn.destroy = function() {
// Code here...
};
})(jQuery);
The code shown in this listing can’t do anything because you haven’t defined the body of init() and destroy(). Nonetheless, you can already call them as if they were native jQuery methods.
Playing with new toys is always exciting, so you might be tempted to add a console.log() statement inside each of the two methods defined (just to prove they’re executed), add the jQuery library and the jquery.jqia.contextMenu.js file to a web page, and then write a statement like the following to see your project in action:
$('p').init();
Unfortunately, if you run the page, right after the output of the console.log() statement you’ll get a scary error message. The reason is that you’ve chosen a common name for your method, so common that jQuery has one of its own. Your method is in conflict with the previously defined jQuery init() method, and this issue raises an important point: namespacing methods.
Properly namespacing your plugin is an important part of your development. It assures that your extension will have a low chance of being in conflict with other plug-ins or even jQuery’s core methods.
Applying this guideline, you could rename your methods as jqiaCustomMenuInit() and jqiaCustomMenuDestroy(). With this change you can safely call both because they won’t conflict with any jQuery native method. Although the change works, the jQuery guidelines discourage claiming more than one namespace to avoid cluttering $.fn. The suggested solution, employed by a lot of top plugins, is to collect all the plugin’s methods in an object literal (usually called methods) and call them using a single method that accepts a string containing the method’s name to execute.
To give you an idea, let’s say that your call-all-the-methods method is named jqiaContextMenu. Using it, you can execute the destroy() method as follows (let’s forget about parameters for now):
$('#element').jqiaContextMenu('destroy');
Following this rule, you can turn the code in listing 12.1 into that shown in the next listing.
Listing 12.2. Revisited version of Jqia Context Menu plugin


Inside the outermost anonymous function, you set up the default options for the plugin parameters . Then you declare an object literal containing the methods you need (with an empty body at the moment)
.
The second part of the code is the most interesting and it’s really clever. First, you assign an anonymous function to a new property of $.fn, called jqiaContextMenu . Doing so, you’re claiming only one name for all your methods instead of one for each method, as the guidelines suggest. Inside this function, you test if the first argument passed, method, has a corresponding property inside the methods variable
. If so, you use an advanced JavaScript technique that uses JavaScript’s apply() and call() functions to execute the required method. apply() is used to set the context of the function (this) to the set of elements in the jQuery collection and to forward to the invoked method all the parameters passed but the first one to your plugin (because the first is the name of the method to invoke). Since arguments isn’t a real array (it’s called an array-like object), you use array’s slice() method and call() to remove the first argument from arguments.
Note
If you need to learn or refresh your knowledge of apply() and call(), please refer to the appendix.
If the first test fails, you check if the first parameter is an object . In such cases you invoke your init() method, forwarding to it all the parameters passed to jqia-ContextMenu(). The reason is that if the user calls jqiaContextMenu() passing the object containing the options, you assume that the user wanted to initialize the plugin and invoke its default action. In this case, too, you use apply() to set the context of the function to the set of elements in the jQuery collection and to forward the arguments to the invoked method. Finally, if both tests fail, you raise an exception using the $.error() utility function
.
As you can see, the update you’ve made to your code is effective and enables you to use only one namespace (jqiaContextMenu) for all the methods. The same rule we discussed in this section is valid for events bound and data stored by your plugin. Let’s discover more.
Leave a Reply