Starter Template for Creating a jQuery Plugin

18. January 2012

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

jQuery, Programming , ,

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading