Boilerplate code to help build stateful jQuery widgets.
If you are not using the jQueryUI Widget Factory to build stateful jQuery widgets, you might feel lost about how to properly organize your jQuery plugin code. jqBoilerplate uses the Revealing Module Design Pattern to organize and provide structure to a stateful jQuery widget.
// jqBoilerPlate - jQuery Stateful Plugin Boilerplate
// (c) 2012 Greg Franko
// jqBoilerplate may be freely distributed
// under the MIT license
/*
Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post]
(http://benalman.com/news/2010/11/immediately-invoked-function-expression/)
that locally passes in `jQuery`, the `window` object, the `document` object,
and an `undefined` variable. The `jQuery`, `window` and `document` objects
are passed in locally to improve performance (JavaScript first searches for
a variable match within the local variables set before searching the global
variables set). All of the global variables are also passed in locally to
be minifier friendly. `undefined` can be passed in locally, because it is not
a reserved word in JavaScript
*/
(function ($, window, document, undefined) {
/*
ECMAScript 5 Strict Mode: [John Resig Blog Post]
(http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/)
*/
"use strict";
//Plugin name (Change this)
var pluginName = "defaultName",
//Plugin version number (Change this)
pluginVersion = "0.1.0",
//Plugin Object
// ------------
// Holds all of the plugin logic
/*
**Convention:** Methods or properties starting with `_` are meant to be
private. You can make them public by including them in the return statement
at the bottom of the Constructor
*/
Plugin = function(element, options, dataName) {
//Self (Add to this)
// -----------------
// Stores all of the `Plugin` object instance variables
var self = {
//The DOM element that called the plugin
element: element,
//The DOM element that called the plugin (wrapped in a jQuery object)
$element: $(element),
//The plugin options object
options: options,
//The name of the plugin
dataName: dataName
},
//_Callback Support
// ----------------
// Calls the function passed in as the parameter
_callbackSupport = function(callback) {
//Checks to make sure the parameter passed in is a function
if($.isFunction(callback)) {
/*
Calls the method passed in as a parameter and sets the context to
the `Plugin` object, which is stored in the jQuery `data()`
method. This allows for the `this` context to reference the
Plugin API Methods in the callback function. The original element
that called the plugin(wrapped in a jQuery object) is the only
parameter passed back to the callback
*/
callback.call(self.$element.data(dataName), self.$element);
}
//Maintains chainability
return this;
},
//_Events (Add to this)
// --------------------
// Adds plugin event handlers
_events = function() {
//Maintains chainability
return this;
},
//Get Option
// ---------
// Returns a single plugin option
getOption = function(key, callback) {
/*
Returns the plugin option if it exists, and returns undefined if the
option does not exist
*/
return self.options[key] || undefined;
},
//Get Options
// ----------
// Returns all of the plugin options
getOptions = function(callback) {
//Returns an object of all of the plugin's options
return self.options || undefined;
},
//Set Option
// ---------
// Replaces a single existing plugin option
setOption = function(key, value, callback) {
//Makes sure a string is passed in
if(typeof key === "string") {
//Sets the plugin option to the new value provided by the user
self.options[key] = value;
}
//Provides callback function support
_callbackSupport(callback);
//Maintains chainability
return this;
},
//Set Options
// ----------
// Accepts an object to replace plugin options properties
setOptions = function(newOptions, callback) {
//If the passed in parameter is an object literal
if($.isPlainObject(newOptions)) {
/*
Uses the jQuery `extend` method to merge the user specified
options object with the self.options` object to create a new
object. The options variable is set to the newly created
object.
*/
self.options = $.extend({}, self.options, newOptions);
}
//Provide callback function support
_callbackSupport(callback);
//Maintains chainability
return this;
},
//Disable (Add to this)
// --------------------
// Disables the DOM element created by the plugin
disable = function(callback) {
//Provides callback function support
_callbackSupport(callback);
//Maintains chainability
return this;
},
//Enable (Add to this)
// -------------------
// Enables the DOM element created by the plugin
enable = function(callback) {
_callbackSupport(callback);
//Maintains chainability
return this;
},
//Destroy (Add to this)
// --------------------
// Brings the page back to it's intial state
destroy = function(callback) {
//Provides callback function support
_callbackSupport(callback);
//Maintains chainability
return this;
},
//Create (Add to this)
// -------------------
// Constructs the plugin
create = function(callback) {
//Provides callback function support
_callbackSupport(callback);
//Maintains chainability
return this;
};
//Public API (Add to this if you create custom public methods/properties)
// -----------------------
// All of these methods or properties are public
return {
//**version**: The current version of the plugin
version: pluginVersion,
//**self**: Object holding all of the plugin instance properties
self: self,
/*
**getOption**: Returns a single plugin option.
Accepts one parameter (String key)
*/
getOption: getOption,
/*
**getOptions**: Returns an object containing all of the current
plugin options
Does not accept parameters
*/
getOptions: getOptions,
/*
**setOption**: Sets a single plugin option.
Accepts two parameters (String key, value)
*/
setOption: setOption,
/*
**setOptions**: Sets or adds new plugin option settings.
Accepts one parameter (Object newOptions)
*/
setOptions: setOptions,
/*
**disable**: Disables the DOM element associated with the plugin
Does not accept parameters
*/
disable: disable,
/*
**enable**: Enables the DOM element associated with the plugin
Does not accept parameters
*/
enable: enable,
/*
**destroy**: Removes all plugin events, data, and DOM elements
Does not accept parameters
*/
destroy: destroy,
/*
**create**: Constructs the plugin
Does not accept parameters
*/
create: create
};
};
//PLUGIN DEFINITION
// ----------------
// Adds the plugin method to the jQuery prototype object
$.fn[pluginName] = function (options) {
//Maintains chainability for all calling elements
return this.each(function () {
/*
Stores the calling element and the data name into local variables,
instantiates the plugin variable (which will hold the Plugin
object), and instantiates an empty object literal (which will be
used to dynamically create a jQuery custom pseudo selector)
*/
var element = $(this), plugin, dataName = pluginName, obj = {};
/*
Returns early if the calling element already has a plugin
instance associated with it inside of the jQuery `data` method
*/
if ($.data(element[0], dataName)) {
return;
}
/*
Uses the jQuery `extend` method to merge the user specified
options object with the `self.options`object to create a new
object. The options variable is set to the newly created
object.
*/
options = $.extend({}, $.fn[pluginName].options, options);
// Instantiates a new `Plugin` object and creates the plugin
plugin = new Plugin(this, options, dataName).create();
/*
Stores the new `Plugin` object in the calling element's
jQuery `data` method
*/
$.data(element[0], dataName, plugin);
/*
Uses the name of the plugin to create a dynamic property
of an empty object literal
*/
obj[pluginName] = function(elem) {
/*
Returns all DOM elements that have jQuery `data()`
created by the plugin
*/
return $(elem).data(dataName) !== undefined;
};
//Adds custom jQuery pseudo selectors
$.extend($.expr[":"], obj);
//end extending jQuery pseudo selectors
}); //end return statement
}; //end plugin
//Default plugin Options (Add to this)
// -----------------------------------
// Adds default options to the plugin
$.fn[pluginName].options = {
};
// End of Plugin
}(jQuery, window, document));
//passes in the `jQuery`, `window`, and `document` global objects locally
The Revealing Module Pattern uses closures to allow both private and public plugin properties and methods. Privacy is very useful when you want to provide a public API while also hiding certain plugin functionality from a user.
-Provides a ready-made public API and private methods (All private methods are preceded with an underscore)
-Protects against multiple plugin instances being created
-Provides a custom jQuery pseudo-selector for your plugin
-Default plugin options can be retrieved and set at any time using the 4 completed methods provided (getOption(), getOptions(), setOption(), and setOptions)
-Callback function and chaining support are built-in
-A solution for dealing with the context of the this keyword (all instance properties are inside of an object literal called self)
-Common methods used with stateful plugins are included (events, disable, enable, destroy, create). These methods are blank, since your custom jQuery plugin logic will go here.
1. Download jq-boilerplate.js
2. Change the pluginName and pluginVersion variables at the top of the file to your jQuery plugin name and version.
3. Write the custom logic for the create(), destroy(), enable(), disable(), and _events().
4. You just created a stateful jQuery widget! Celebrate!
Call your plugin method on a jQuery object. This example is assuming your plugin is named coolPlugin, so replace the name coolPlugin with the name of your plugin.
//Creating your plugin!
var plugin = $("#someElement").coolPlugin().data("coolPlugin");
Test out your new jQuery pseudo selector
/*
The jQuery pseudo selector that was created for the coolPlugin that tells you which
elements have been called by the coolPlugin
*/
$(":coolPlugin").each(function() {
console.log(this.id);
});
Set options when the plugin is created or after the plugin is created
Setting an option when the plugin is created
//Creating your plugin and setting options!
var plugin = $("#someElement").coolPlugin({ someOption: false }).data("coolPlugin");
Setting an option after the plugin is created
//Creating your plugin!
var plugin = $("#someElement").coolPlugin().data("coolPlugin");
//Setting an option after the plugin is created!
plugin.setOption("someOption", false);
Questions will be added here from the Github Issues Page. Also, more demos/documentation will be provided on request.