Question

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?

Was it helpful?

Solution

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');
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top