Reputation: 1108
I've used this plugin boilerplate as a starting point to create a plugin that allows me to make direct calls to it's methods:
;(function ($, undefined ) {
var pluginName = 'myPlugin',
defaults = {
option1: 'none',
option2: 'none',
};
function Plugin( element, options ) {
this.element = element;
this.options = $.extend({}, defaults, options) ;
this.someBool = undefined;
this.init();
}
Plugin.prototype = {
init: function () {
this.someBool = false;
},
someMethod: function (selector) {
var self = this;
$(selector).each(function () {
// do something to the element using self.options
self.someBool = true;
};
}
someOtherMethod: function (selector, myBool) {
var self = this;
$(selector).each(function () {
// do some other thing to the element using self.options
self.someBool = myBool;
};
}
}
$.fn[pluginName] = function (options) {
var args = arguments;
if (options === undefined || typeof options === 'object') {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName, new Plugin( this, options ));
}
});
} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
var returns;
this.each(function () {
var instance = $.data(this, 'plugin_' + pluginName);
if (instance instanceof Plugin && typeof instance[options] === 'function') {
returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
}
if (options === 'destroy') {
$.data(this, 'plugin_' + pluginName, null);
}
});
return returns !== undefined ? returns : this;
}
};
}(jQuery));
So, if I call the plugin with no arguments or with an object as argument, it instantiates and initializes it. If I pass a string, it looks for a method with that name and pass the other arguments to it. Right now I'm using it like this (note that #someElement
is only used to store the instance, nothing else):
$('#someElement').myPlugin({
option1: 'value1',
option2: 'value2',
});
$('#someElement').myPlugin('someMethod', '#someOtherElement');
$('#someElement').myPlugin('someOtherMethod', '#yetAnotherElement', false);
It kinda works, but I would like to be able to call these methods using different selectors while working with the same instance, a singleton, if you will. Something like:
$.myPlugin({
option1: 'value1',
option2: 'value2',
});
$('#someOtherElement').myPlugin('someMethod');
$('#yetAnotherElement').myPlugin('someOtherMethod', false);
I'm not much of a javascript programmer, but as far as I understand, I must store it's instance in a place other than the elements I'm using to call it, maybe in the window
object or jQuery namespace? What about being able to call it both with and without a selector, is it doable?
Upvotes: 1
Views: 1848
Reputation: 1108
I was able to set options globally instead of per instance by looking at this link. This does not provides a singleton plugin as I initially requested, but it is, in fact, even better this way, because I can have both global and per element options.
$[pluginName] = $.fn[pluginName] = function (options) {
var args = arguments;
if (options === undefined || typeof options === 'object') {
if (!(this instanceof $)) {
$.extend(defaults, options);
}
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
});
} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
var returns;
this.each(function () {
var instance = $.data(this, 'plugin_' + pluginName);
if (!instance) {
instance = $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
if (instance instanceof Plugin && typeof instance[options] === 'function') {
returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
}
if (options === 'destroy') {
$.data(this, 'plugin_' + pluginName, null);
}
});
return returns !== undefined ? returns : this;
}
};
And now I can call the script just like I've described in my question.
As a side note, if you look at my previous questions, you'll see that I have answered most of them. Mostly because very few people bothered to even try to help. I don't think that these questions were neither too basic or too difficult to bother to answer... too specific, perhaps? I would love to get some feedback on that.
Upvotes: 2
Reputation: 10328
There are jQuery plugins that act as singletons. jQuery cookie is a example that is short and easy to read. It should be no problem to adapt its pattern to your requirements.
In essence, singleton plugins simply define themselves directly on $
, as in
$.myplugin = function(...)
and skip the whole
return this.each(function () { }
part, since they are not being initialized on jQuery elements. So it's mostly a matter of leaving things out ;)
Upvotes: 2