Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would I add a method to this jQuery plugin pattern?

Tags:

jquery

plugins

I'm using the following code as the basis for a plugin I'm working on for a project - it's from an article on Smashing Magazine located here under the heading 'A Lightweight Start':

http://coding.smashingmagazine.com/2011/10/11/essential-jquery-plugin-patterns/

It's been working fine for my purposes so far, but the rest of the article goes off on a tangent and talks about what jQuery UI widgets which I assume I would need the jQuery UI library for, which I don't really want to use.

/*!
 * jQuery lightweight plugin boilerplate
 * Original author: @ajpiano
 * Further changes, comments: @addyosmani
 * Licensed under the MIT license
 */

// the semi-colon before the function invocation is a safety
// net against concatenated scripts and/or other plugins
// that are not closed properly.
;(function ( $, window, document, undefined ) {

    // undefined is used here as the undefined global
    // variable in ECMAScript 3 and is mutable (i.e. it can
    // be changed by someone else). undefined isn't really
    // being passed in so we can ensure that its value is
    // truly undefined. In ES5, undefined can no longer be
    // modified.

    // window and document are passed through as local
    // variables rather than as globals, because this (slightly)
    // quickens the resolution process and can be more
    // efficiently minified (especially when both are
    // regularly referenced in your plugin).

    // Create the defaults once
    var pluginName = 'defaultPluginName',
        defaults = {
            propertyName: "value"
        };

    // The actual plugin constructor
    function Plugin( element, options ) {
        this.element = element;

        // jQuery has an extend method that merges the
        // contents of two or more objects, storing the
        // result in the first object. The first object
        // is generally empty because we don't want to alter
        // the default options for future instances of the plugin
        this.options = $.extend( {}, defaults, options) ;

        this._defaults = defaults;
        this._name = pluginName;

        this.init();
    }

    Plugin.prototype.init = function () {
        // Place initialization logic here
        // You already have access to the DOM element and
        // the options via the instance, e.g. this.element
        // and this.options
    };

    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function ( options ) {
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                $.data(this, 'plugin_' + pluginName,
                new Plugin( this, options ));
            }
        });
    }

})( jQuery, window, document );

I now need to add a method to this but I'm pretty clueless as to how to do so.

The method needs to work in such a way that an instance of what the plugin is creating on the page can have a property dynamically changed by calling the method with a value via the console (eventually this will occur via some other process, but console is good for now).

How would I go about amending the code above to allow for this? Or am I barking up the wrong tree?

Any help would be greatly appreciated, complex JavaScript can leave me a bit lost in the dark at times I'm afraid but I like to try to do things as 'best practices' as possible.

like image 603
Rich C Avatar asked Jun 11 '12 10:06

Rich C


1 Answers

The jQuery documentation strongly recommends calling plugin methods by passing a string to the main plugin method. This is to stop the $.fn namespace becoming cluttered by the methods of your plugin. So you do something like this:

$.fn.yourPlugin = function(options) {
    if (typeof options === "string") {
        //Call method referred to by 'options'
    } else {
        //Setup plugin as usual
    }
};

In your pattern, you already have the perfect place to define your methods: Plugin.prototype. For example, to add a changeColor method:

Plugin.prototype.changeColor = function(color) {
    $(this.element).css("color", color);
}

Notice the use of $(this.element). That's because in the Plugin constructor, a property element is defined, and the element on which the plugin is being applied is assigned to it:

this.element = element;

That is the actual DOM element, not a jQuery object, hence the need to call jQuery on it.

So now you have a method, you need to add a mechanism to call it. Following the recommendations from the jQuery docs:

$.fn[pluginName] = function ( options ) {
    return this.each(function () {
        if (typeof options === "string") {
            var args = Array.prototype.slice.call(arguments, 1),
                plugin = $.data(this, 'plugin_' + pluginName);
            plugin[options].apply(plugin, args);
        } else if (!$.data(this, 'plugin_' + pluginName)) {
            $.data(this, 'plugin_' + pluginName,
            new Plugin( this, options ));
        }
    });
};

You can then call the changeColor method like this:

$("#example").defaultPluginName("changeColour", "red");​​​​​​​​​​​​​​​​​​​​​​​​​​​

Here's a fiddle with a working example. You may want to add some check around the method calling code to make sure the plugin has actually be instantiated on the element(s) you are calling it on.

like image 158
James Allardice Avatar answered Oct 05 '22 15:10

James Allardice