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.
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>
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/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With