Every time I needed to create a jQuery plugin, I would debate with myself on how to structure the code. It occurred to me that it would be helpful to stub out a sample plugin template that I could grab and jump right into coding.
After looking around at various jQuery plugin patterns, I came up with the template at the end of this post. I think it has a nice structure, but would enjoy hearing any suggestions. The one thing I may add to this in the future is the ability to programmatically uninstall the plugin.
Here are some samples of how you might invoke the plugin and then call it's API.
// Install the plugin on all matching elements
$("div.myPlugin").myPlugin();
// Install the plugin and override a default setting
$("div.myPlugin").myPlugin({
playPauseSelector:'#playbutton'
});
// Control multiple instances at once
// and also maintain the fluent API using
// the jQuery plugin function to call the API
$("div.myPlugin").myPlugin("play", 2);
$("div.myPlugin").myPlugin("play", 2).myPlugin("pause");
// Control a single instance by accessing the attached API
// Only the officially supported API methods can be called
$("div.myPlugin").get(0).MyPlugin.play(2);
Here is the code:
NOTE: Some parts of the code are included only to illustrate aspects of the structure. See the code comments for more explanation.
(function ($) {
// Create the plugin jQuery function
$.fn.myPlugin = function (optionsOrCommand, param) {
// Setup the default options
var defaultOptions = {
playPauseSelector: '.MyPluginPlayPauseButton',
playingClass: 'playing',
pausedClass: 'paused'
};
// Define a function to setup the plugin instance
var create = function (root, options) {
// Grab a reference to the root DOM element that is the target of the plugin
var _root = $(root);
var _playPauseButton = null;
// Update the settings with any overrides
var _opts = $.extend({}, defaultOptions, (options || {}));
// Create internal helper methods
var _play = function(idx) {
_playPauseButton.removeClass(pausedClass).addClass(playingClass);
};
var _pause = function() {
_playPauseButton.removeClass(playingClass).addClass(pausedClass);
};
// Define an init function to kick off the plugin functionality
var _init = function () {
_playPauseButton = $(playPauseSelector, _root);
_playPauseButton.bind('click', function() {
var self = $(this);
if (self.hasClass(playingClass)) {
_pause();
} else {
_play();
}
});
};
// Return an object containing a reference to the API and the init method
// We don't want the init in the API so it is separated here
return {
controller: {
init: function () {
_init();
}
},
api: {
pause: function () {
_pause();
},
play: function (idx) {
_play(idx);
}
}
};
};
// Cycle through each matching element and return them
// so as not to break the jQuery fluent API
return this.each(function () {
// Grab a reference to the root element
var root = this;
// Determine whether or not the plugin is already installed
var exists = !(root.MyPlugin === undefined || root.MyPlugin === null);
// Initialize the optionsOrCommand so we can handle either input
if (optionsOrCommand === undefined || optionsOrCommand === null) {
optionsOrCommand = {};
}
// If the optionsOrCommand is a string then map it to the API
if (optionsOrCommand.constructor == String) {
if (exists) {
switch (optionsOrCommand) {
case 'pause':
case 'play':
if (typeof root.MyPlugin[optionsOrCommand] === 'function') {
root.MyPlugin[optionsOrCommand](param);
}
break;
default:
return;
}
}
return;
}
// If the plugin is not installed then create it and apply the API
// to the DOM element.
if (!exists) {
var plugin = create(root, optionsOrCommand);
root.MyPlugin = plugin.api;
plugin.controller.init();
}
});
};
})(jQuery);
Here are some links to other interesting plugin patterns:
JQUERY GENERATOR BY Kees C. Bakker
Creating a jQuery plugin
Keeping the plugin and jQuery separate
8aecadf1-7aaf-4716-b759-1d544038571e|1|5.0
jQuery, Programming
jQuery, Best Practices, Plugins