Thoughtful jQuery Plugin Development
Why I wrote this issue
I was complaining on twitter, as usual. Then, two developers I respect very much (Chistoph Pojer and Rebecca Murphey) asked me to explain my woes. I believe in a lot of peculiar things--like green jello and casserole--but I don't believe in complaining about something without providing a solution. So, I've turned this into a series of articles on how to write extendable jQuery plugins, so check them out above. Or, continue reading some more whining below.jQuery plugins are hard to use.
No, I don’t mean the syntax is hard, most of the time it’s as easy as $('#el').doStuff()
. Rather, getting the the plugin to meet my requirements is impossible most of the time—unless I monkey patch the plugin’s source code. Why? 99% of them are immutable functions instead of mutable objects.
When I use somebody else’s code, I put a lot of effort in to leaving the source alone*. Unfortunately, I can’t always do that. Most of the plugins are mutable functions with event bindings unbindable, css styles dropped inline, and all sorts of things. This doesn’t have to be the case.
The issue at hand, from the jQuery docs
Here’s a code sample from the jQuery docs on authoring plugins:
(function( $ ){
$.fn.myPlugin = function() {
// Do your awesome plugin stuff here
};
})( jQuery );
Right from the start, none of the “awesome plugin stuff” is mutable. It’s safely (har har) tucked away into an immediately-invoked function expression. I use IIFE’s regularly (that’s my textmate tab trigger) and believe I have respect for the global namespace—but you can’t hide your entire plugin like it’s your underpants and expect anybody but you to be able to use it.
Moving on through the docs we see this example:
(function( $ ){
var methods = {
init : function( options ) { // THIS },
show : function( ) { // IS },
hide : function( ) { // GOOD },
update : function( content ) { // !!! }
};
$.fn.tooltip = function( method ) {
// Method calling logic
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.tooltip' );
}
};
})( jQuery );
Look at the var methods
object literal. What if my requirements for showing the tooltip are different than what the plugin author decided? Let’s consider the show
method to be this:
show : function( ) { self.fadeIn() },
But I need this:
show: function( ) { self.slideDown() }
There’s nothing left for me to do other than hack the source and change the method. I have no access to the methods
object literal. I’m not suggesting a plugin should allow me to change every line of code somehow—well, maybe I am—but there are a lot of things that I ought to be able to change.
There’s a lot of jQuery out there. Unfortunately, only a few have been flexible enough for me to use as I’ve gone looking. The rest I’ve had to hack the source to meet the requirements. If plugin developers can follow some of these tips, they’ll have far more useful code.
* If I find a bug or think of a feature that fits, I’ll fork it on github and send a pull request. Otherwise, I try to leave the source code alone.
-
Providing Options in jQuery Plugins
October 05, 2010Nothing new or extraordinary here, but I run across enough jQuery plugins that don't provide options to warrant writing an article about it. You can meet a lot more use cases for your plugin if you provide the developer with some options.
-
Use Your Fn jQuery Namespace
October 05, 2010Every plugin gets a namespace on the jQuery prototype. If you keep all of your functions, methods, and variables scoped inside the jQuery.fn function, others can't extend or alter the functionality of your plugin. Instead, take advantage of your block on jQuery street and let other developers take advantage of your plugin.
-
Authoring jQuery Plugins With Object Oriented JavaScript
October 05, 2010Instead of wrapping all the plugin logic inside the $.fn.disables = fn, keep all the logic outside in its own object and just use effin' to add your object to the jQuery API. It allows others to extend your plugin with ease, and allows you to skip the whole jQuery API, if you so desire.
-
jQuery.addObject - Managing a Plugin's State With the jQuery API
October 05, 2010Most plugins ought to provide a way for the developer to interact with it. Think of the holy accordion. Outside of just the click event on the togglers, you should provide a way to show a certain panel arbitrarily. The jQuery.addObject method to the rescue.