Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create jQuery plugin with configuration settings

I've been using the following design patter to create jQuery plugins. I'm pretty sure I got the concept from the jQuery homepage, however, it appears to no longer be published there.

I recently attempted to access the settings variable within a method (i.e. someOtherMethod ()) other than the init() method, and experienced an error as settings was not defined. I see the cause as settings is isolated to the init() method.

If I move settings outside of this method, I could then access it from different methods, however, each instance when the plugin is applied will not have its unique settings variable which is unacceptable. For instance, $('#id1, #id2').myPlugin({x:111}); should have a common settings variable, however $('#id1').myPlugin({x:111}); $('#id2').myPlugin({x:222}); should each have their unique settings variable.

Given the below design pattern as a starting point, how can I access the settings variable from all methods associated with the plugin, yet have a unique settings variable each time the plugin is applied?

(function( $ ){

    var defaults={
        x : 123,
        y : 321
    };
    // var settings={}; //Should settings be defined here???

    var methods = {
        init : function( options ) {
            var settings = $.extend(defaults, options  || {});
            //settings = $.extend(defaults, options  || {}); //Should settings just be updated and not defined here?
            return this.each(function(){
                //whatever
            });
        },

        someOtherMethod : function() {
            return $(this).each(function(){
                //do whatever and use settings variable as applicable
            })
        },
    };

    $.fn.myPlugin = function(method) {
        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.myPlugin' );
        }    
    };

}( jQuery ));

$('#id1, #id2').myPlugin({x:111});  //Sets x=111 in settings for both
$('#id3').myPlugin({x:333});        //Sets x=333 in settings.
$('#id3').myPlugin('someOtherMethod');  //Will have access to x=333 in settings.
like image 898
user1032531 Avatar asked Mar 16 '23 01:03

user1032531


2 Answers

You're going to want to save the settings object per-element so that the settings will persist across different selectors. The best way to do this is to use jQuery.data to attach a settings object to the element. This way, the settings will persist each time the element is selected, regardless of how it is selected.

Then, in the .each call of someOtherMethod, you can access this data using jQuery.data on the element.

Also, each individual element is going to need a separate settings object to avoid overwriting shared settings, so this:

var settings = $.extend(defaults, options  || {});

Will need to be replaced with this:

var settings = $.extend({}, defaults, options  || {});

Otherwise the defaults object will be overwritten each time with new settings properties, and shared among all the elements.

In this example, I have created a variable name internalPrefix with the value of '_myPlugin' for the key under which to save the data using jQuery.data. I've added some tests at the bottom to show how it can be initialized on different ways, but the method can be called and still be aware of the settings used to initialize on the element.

#Working Example:

(function( $ ){

    var defaults={
        x : 123,
        y : 321
    };
    //A variable to save the setting data under.
    var internalPrefix = '_myPlugin';

    var methods = {
        init : function( options ) {
            return this.each(function() {
                //Setup the settings object.
                var settings = $.extend({}, defaults, options || {});
                //Save the settings to the element.
                $(this).data(internalPrefix, settings);
            });
        },

        someOtherMethod : function() {
            return this.each(function() {
                //Get the existing settings.
                var settings = $(this).data(internalPrefix);
                //Example:
                $('<code></code>').text(JSON.stringify(settings)).appendTo(this);
            })
        },
    };

    $.fn.myPlugin = function(method) {
        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.myPlugin' );
        }
    };

}( jQuery ));

//Initialize the plugin different ways.
$('.group-1').myPlugin();
$('.group-2').myPlugin({
    x : 42,
    y : 1337
});

//Cal the methods on those different ways.
$('p').myPlugin('someOtherMethod');
<p class="group-1">group 1</p>
<p class="group-1">group 1</p>
<p class="group-2">group 2</p>
<p class="group-2">group 2</p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
like image 54
Alexander O'Mara Avatar answered Mar 26 '23 11:03

Alexander O'Mara


Updated, Added {} as first argument to $.extend()

If, however, you want to preserve both of the original objects, you can do so by passing an empty object as the target:

var object = $.extend({}, object1, object2);


Try setting defaults as property of methods , defining settings within init

var settings = $.extend({}, methods.defaults, options || {});

setting this element .data() with settings before call to .each()

return this.data(settings).each(function() {})

settings would then be unique for each element ; accessible utilizing $(this).data() , returning defaults if options not passed as argument to $.fn.myPlugin, updating defaults if options passed as argument to $.fn.myPlugin


(function($) {

  var defaults = {
    x: 123,
    y: 321
  };

  var methods = {
    init: function(options) {
      // extend `methods.defaults` with `options`
      var settings = $.extend({}, methods.defaults, options || {});
      return this.data(settings).each(function() {
        //whatever
        console.log("init", this.id, $(this).data());
      });
    },

    someOtherMethod: function() {
      return $(this).each(function() {
        //do whatever and use settings variable as applicable
        console.log("someOtherMethod", this.id, $(this).data());
      })
    },
  };
  // set `defaults` as property of `methods`
  methods.defaults = defaults;

  $.fn.myPlugin = function(method) {
    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.myPlugin');
    }
  };

}(jQuery));

$('#id1, #id2').myPlugin({
  x: 111
});
$("#id1").myPlugin({
  y: 222
});
$("#id2").myPlugin({
  y: 333
});
$("#id2").myPlugin("someOtherMethod");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div id="id1"></div>
<div id="id2"></div>

jsfiddle http://jsfiddle.net/z28wwnLh/1/

like image 38
guest271314 Avatar answered Mar 26 '23 12:03

guest271314