I am working on a jQuery plugin, but I am having some trouble with the design pattern, which combines the defaults and options, data and namespacing techniques from jQuery's best practices. Here's the abstracted version of my code:
(function($) {
var defaults = {
key1: 'value1',
key2: 'value2'
};
var settings = {};
var methods = {
init: function() {
return this.each(function() {
var $this = $(this), data = $this.data('pluginname');
console.log('init called');
// If the plugin hasn't been initialized yet
if (!data) {
//Do more setup stuff here
$this.data('pluginname', {
key3: 'value3',
key4: 'value4'
});
}
//test for settings and data
console.log(settings);
console.log(data);
});
},
methodname: function() {
return this.each(function() {
var $this = $(this), data = $this.data('pluginname');
console.log('methodname called');
//test for settings and data
console.log(settings);
console.log(data);
});
}
};
$.fn.pluginname = function(method, options) {
settings = $.extend({}, defaults, options);
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.pluginname' );
}
};
$(document).ready(function() {
$('body').pluginname();
$('body').pluginname('methodname', {key1: 'overriding default value for key 1'});
});
})(jQuery);
If you run that code with the latest version of jQuery you will see that I am calling both the init
and methodname
functions and logging the settings
and data
objects in each. In the methodname
call, I can access both settings
and data
, but in the init
call itself, the data
object returns undefined. If I set a breakpoint in the script at line 21, I can call back the data
object with $this.data('pluginname')
in the console. Anyone see what I am doing wrong here? I should just be able to write data.key3
inside the init, function, right?
In your init
method, at the very beginning of the .each
loop you assign the object stored in the currently iterated element to your data
variable. If there is no data available for the specified key, data
is undefined.
You then test data
for truthiness, and if it is evaluates to false you go ahead and assign a data object to the current element.
Then later on, you call console.log(data);
and it gives you undefined
. This is expected, as data
was initially assigned undefined
- and that's what it still refers to. To fix:
// if undefined
if (!data) {
//Do more setup stuff here
$this.data('pluginname', {
key3: 'value3',
key4: 'value4'
});
data = $this.data('pluginname');
}