jquery-boilerplate / jquery-patterns

A variety of jQuery plugin patterns for jump starting your plugin development
1.59k stars 242 forks source link

this.[functionOne] is not a function #28

Closed lawlesscreation closed 11 years ago

lawlesscreation commented 11 years ago

Hi, could someone explain where I am going wrong. I'm trying to use the jQuery boilerplate but having trouble when adding functions and calling them:

/*!
 * jQuery lightweight plugin boilerplate
 * Original author: @ajpiano
 * Further changes, comments: @addyosmani
 * Licensed under the MIT license
 */

// the semi-colon before the function invocation is a safety
// net against concatenated scripts and/or other plugins
// that are not closed properly.
;(function ( $, window, document, undefined ) {

    // undefined is used here as the undefined global
    // variable in ECMAScript 3 and is mutable (i.e. it can
    // be changed by someone else). undefined isn't really
    // being passed in so we can ensure that its value is
    // truly undefined. In ES5, undefined can no longer be
    // modified.

    // window and document are passed through as local
    // variables rather than as globals, because this (slightly)
    // quickens the resolution process and can be more
    // efficiently minified (especially when both are
    // regularly referenced in your plugin).

    // Create the defaults once
    var pluginName = "defaultPluginName",
        defaults = {
            propertyName: "value"
        };

    // The actual plugin constructor
    function Plugin( element, options ) {
        this.element = element;

        // jQuery has an extend method that merges the
        // contents of two or more objects, storing the
        // result in the first object. The first object
        // is generally empty because we don't want to alter
        // the default options for future instances of the plugin
        this.options = $.extend( {}, defaults, options) ;

        this._defaults = defaults;
        this._name = pluginName;

        this.init();
    }

    Plugin.prototype = {

        init: function() {
            // Place initialization logic here
            // You already have access to the DOM element and
            // the options via the instance, e.g. this.element
            // and this.options
            // you can add more functions like the one below and 
            // call them like so: this.yourOtherFunction(this.element, this.options).

            $(this.element).each(function() {
                console.log('Main function');

                this.functionOne(this.element, this.options);
            });
        }, 

        functionOne: function(el, options) {
            console.log('functionOne');

            this.functionTwo(el, options);
        },

        functionTwo: function(el, options) {
            console.log('functionTwo');
        }
    };

    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function ( options ) {
        return this.each(function () {
            if (!$.data(this, 'plugin_' + pluginName)) {
                $.data(this, 'plugin_' + pluginName,
                new Plugin( this, options ));
            }
        });
    }

})( jQuery, window, document );

This simple calling of functions results in the following console log:

Main function

TypeError: this.functionOne is not a function
this.functionOne(this.element, this.options);

Did I miss something? Reading the comments in the script, I think I'm calling the functions correctly?

Thanks!

yckart commented 11 years ago

You've to assign the this-keyword outside of your each-method:

var self = this;

$(this.element).each(function() {
    console.log('Main function');

    self.functionOne(self.element, self.options);
});

And btw, you don't need to pass this.element and this.options to all your methods. They are already declared in your global scope.

lawlesscreation commented 11 years ago

Brilliant, I thought I was going mad. Thanks!