I’m working on a jQuery plugin. When the plugin runs, the first thing it does is determine its settings. It does this by taking some default settings and overriding some or all of them with whatever the user passed in.
Here’s a simplified version:
(function( $ ) {
$.fn.somePlugin = function(userOptions) {
// Short name for internal use - exposed below for external modification
var defaults = $.fn.somePlugin.defaults;
// Decide settings
// User settings overrule defaults, but merge both into an empty
// hash so that original defaults hash isn't modified
var settings = $.extend(true, {}, defaults, userOptions);
settings.alerter.call();
// More code, etc.
}
$.fn.somePlugin.defaults = {
name: 'Captain Slappy von Martinez, Esquire, DDS',
favoriteColor: 'red',
alerter: function(){alert("I got bones!");}
}
})( jQuery );
So, if you call the plugin like this:
$('div').somePlugin({alerter: function(){alert('No bones here!');}});
… you override the default alerter function, but use the default favoriteColor.
I’m defining the defaults outside the plugin itself so that they are publicly accessible. So if you want to change the default value for favoriteColor, you can just do this:
$.fn.somePlugin.defaults.favoriteColor = 'blue';
… and that will change it for every instance on the page after that.
All of this works fine.
Here’s my problem: in one of the default functions, I need to refer to settings. Something like this:
$.fn.somePlugin.defaults = {
name: 'Captain Slappy von Martinez, Esquire, DDS',
favoriteColor: 'red',
alerter: function(){alert("Paint me " + settings.favoriteColor);}
}
But when I try this, I get a Javascript error on the line where the default alerter function is declared: "settings is not defined." True enough: it’s not defined yet when the parser hits that line. It WILL be defined by the time the function runs, but that doesn’t seem to matter.
So my question is: How can I import my default function into the plugin in such a way that it has access to settings?
- Is there a way to delay evaluation of
settingsuntil the function is actually called? - If so, is there a way to make sure it has access to the local scope of the plugin, even though I assume that, as an object, this function is being passed by reference? I know that I can alter the value of
thisinside a function by usingsomeFunction.call(valueToUseForThis), but I don’t know whether I can alter its scope after the fact.
Some Stuff that Doesn’t Work
- Initially, it seemed that if I declared
settingsin the outer, self-executing function, that would make it available to the defaults. But declaring it there causes problems: if I use my plugin multiple times on a page, the instances get their settings mixed up.
Any attempts to change scope after the fact are doomed. There’s no dynamic scoping in JavaScript.
Workaround 1.
Pass settings to the alerter explicitly:
Workaround 2. Pass settings to the alerter implicitly:
Both solutions tested and work well with multiple uses of the plugin. If you have no plans for using
thiskeyword in your alerter, you can use it for referencing settings.The third valid solution, which you and fudgey mentioned, is to attach settings object to the DOM element itself:
Extra fun. Emulating dynamic scope, a.k.a don’t do this
Usage in a plugin: