Thomas
Thomas

Reputation: 5856

Managing scope of event handlers on a jQuery plugin

I'm using jQuery's event system to allow external code to drive my plugin. In my event handlers 'this' is set to the element that the events are bound to, so what's the best way for me to access the plugin's methods themselves?

;(function($, window, document, undefined){
    var pluginName = "book";

    // Standard constructor
    function Plugin(element, options){
        this.element = element;
        this.options = $.extend({}, defaults, options);

        this.init();
    }

    // Simple init
    Plugin.prototype.init = function(){
        this.setBindings();
    }

    // Tie local methods to event channels
    // so that external code can drive the plugin. 
    Plugin.prototype.setBindings = function(){
        var events = {
            'book-open'      : this.open,
            'book-next-page' : this.toNext,
            'book-prev-page' : this.toPrev,
            'book-cover'     : this.toFront,
            'book-back'      : this.toBack
        }

        for(event in events){
            var fn = events[event];
            console.log(event);
            this.$element.on(event, fn);
        }
    };

    // Event Handlers
    Plugin.prototype.open = function(){
        // when called externally 'this' refers
        // to the element the plugin was intialized on.
        // I want to be able to call the plugin's 'private'
        // methods, like someMethod() below.
    };

    /* .... other event handlers ...  */

    // 'Private' plugin methods
    Plugin.prototype.someMethod = function(){
        // do something
    }

    // Wrap and return technique from @ajpiano & @addyosmani
    $.fn[pluginName] = function ( options ) {
        return this.each(function () {
            if ( !$.data(this, "plugin_" + pluginName )) {
                $.data( this, "plugin_" + pluginName,
                    new Plugin( this, options ));
            }
        });
    }

 })(jQuery, window, document);

Upvotes: 1

Views: 1611

Answers (1)

Caleb
Caleb

Reputation: 1088

You can, instead of passing the function itself, call a function that will return the function you want to execute, which a closure around the plugin.

var createBookOpenFunction = function () {
    var self = this; //since you execute this function on the plugin, "this" will be the plugin
    return function () {
        self.open();
    }
};

then, instead of calling...

this.$element.on(event, fn);

you instead call

this.$element.on(event, this.createBookOpenFunction());

so now, when the function is called on the $element, the actual execution is done on the plugin object, because it's closed on "self".
and you can just feed the parameters (if there are any) through the returned function, into the call "self.open()".

Also, this thread may be of help: Controlling the value of 'this' in a jQuery event

(I don't use jQuery directly, so I am unfamiliar with what all is available in the API, but some posts on here seem to have alternate solutions to your problem)

Upvotes: 2

Related Questions