14

Is it good or bad practise writing plugins this way(using class and prototypes), what are disadvatages of this code?

function PluginName(jqueryObject, options) {

}
PluginName.prototype = {
    publicMethod:function() {
    },
    _privateMethod:function() {
    }
}

// Initializing 
var myPluginInstance = new PluginName($(".mySelector"), {myOption:1});
myPluginInstance.publicMethod();
3
  • 1
    Both methods are public, or, accessible with this code. Commented Aug 22, 2011 at 14:48
  • Disadvantage: One cannot use jQuery's fluent interface. Commented Aug 22, 2011 at 14:50
  • Thanks, what is the best way then to declare private method here? Commented Aug 22, 2011 at 14:52

3 Answers 3

29

See the jQuery docs on plugin authoring for best practices:

  • Always wrap your plugin in (function( $ ){ // plugin goes here })( jQuery );
  • Don't redundantly wrap the this keyword in the immediate scope of your plugin's function
  • Unless you're returning an intrinsic value from your plugin, always have your plugin's function return the this keyword to maintain chainability.
  • Rather than requiring a lengthy amount of arguments, pass your plugin settings in an object literal that can be extended over the plugin's defaults.
  • Don't clutter the jQuery.fn object with more than one namespace per plugin.
  • Always namespace your methods, events and data.

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 );

Usage:

$('div').tooltip(); // calls the init method
$('div').tooltip({  // calls the init method
  foo : 'bar'
});
$('div').tooltip('hide'); // calls the hide method
$('div').tooltip('update', 'This is the new tooltip content!'); // calls the update method

Defaults and Options Example

(function( $ ){

  $.fn.tooltip = function( options ) {  

    var settings = {
      'location'         : 'top',
      'background-color' : 'blue'
    };

    return this.each(function() {        
      // If options exist, lets merge them
      // with our default settings
      if ( options ) { 
        $.extend( settings, options );
      }

      // Tooltip plugin code here

    });

  };
})( jQuery );

Usage:

$('div').tooltip({
  'location' : 'left'
});
Sign up to request clarification or add additional context in comments.

1 Comment

How to share data between methods?
8

First, as Spycho said, always wrap your plugin in

(function( $ ){
    $.fn.PluginName = function() {
        // plugin goes here
    };
})( jQuery );

to avoid conflict with other libraries that use the dollar sign.

Second, if you extend the jQuery.fn object the selection called with something like $("#myDiv") is passed to the plugin as this. This way you don't have to pass the selection as a parameter to the plugin as you've done.

Third, this you did correctly, they suggest that you pass options to the plugin as an object rather than individual parameters, this is so you can easily have and override defaults:

(function( $ ){
    $.fn.PluginName = function(options) {
        var settings = { myOption: 1 };
        if (options) {
            $.extend( settings, options );
        }
        // plugin goes here
    };
})( jQuery );

Fourth, the way you've created your _privateMethod doesn't actually make it private, to do so you could follow the pattern jQuery suggests in the plugin authoring guidelines

(function( $ ){
    var methods = {
        publicMethod: function(options) {
           var settings = { myOption: 1 };
            if (options) {
                $.extend( settings, options );
            }
        },
        _privateMethod: function() {}            
    }
    $.fn.PluginName = function(methodName, options) {
        // use some logic to control what methods are public
        if (methodName == "publicMethod") {
            return publicMethod.apply(this, Array.prototype.slice.call( arguments, 1 ));
        }
    };
})( jQuery );

This uses apply and call which are fancy built-in methods of functions for setting the scope of function calls, see the MDN reference to understand what is going on there. This way you actually have control over which methods are public versus private.

EDIT: Finally, if you want to completely maintain jQuery's fluid interface and have your plugin both accept the selection passed by $() and pass it on, in other words, be chainable, your methods need to return the collection of objects they were given:

(function( $ ){
    var methods = {
        publicMethod: function(options) {
           var settings = { myOption: 1 };
            if (options) {
                $.extend( settings, options );
            }
            return this.each(function() {
                this.value = (this.value * 1) + settings.myOption;
            });
        },
        _privateMethod: function() {}            
    }
    $.fn.PluginName = function(methodName, options) {
        // use some logic to control what methods are public
        if (methodName == "publicMethod") {
            return methods.publicMethod.apply(this, Array.prototype.slice.call( arguments, 1 ));
        }
    };
})( jQuery );

See this jsFiddle for the final working example.

Comments

0

The easiest way to write jQuery plugins (especially if they have some internal state) is to use jQuery UI Widget Factory.

I wouldn't recommend to reinvent the wheel and write lots of boilerplate code by yourself.

https://learn.jquery.com/jquery-ui/widget-factory/why-use-the-widget-factory/ https://learn.jquery.com/plugins/stateful-plugins-with-widget-factory/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.