Search code examples
thisdocument-readyjquery-callbackjquery-context

Calling jQuery's ready() with plugin context


My plugin allows you to specify a callback in its options. The plugin may run before the DOM is ready, but I need to make sure the callback only runs once the DOM is ready, so I'm wrapping the callback.call() within a $( document ).ready() handler.

The problem is I want to maintain the plugin's context within the callback. In other words, within the callback, I want this to be the plugin, not document.

This is what I've come up with, but I'm not sure it's really the best way.

function MyPlugin( element, options ){
    this.element = element;
    this.options = $.extend( {}, defaults, options );

    MyPlugin.prototype = {
        functionWithCallback: function(){
            if ( typeof this.options.callback == 'function' )
                $( document ).ready( function( plugin ){ plugin.options.callback.call( plugin ) }( this )
        }
    }
}

That last line is ugly, but it allows me to pass the plugin's this context to the callback.

I would rather do $( document ).ready( this.options.callback ) and be done with it, but then within the callback, this is document which doesn't really help, and doesn't necessarily give me easy access to the element the plugin was called on...

Is there a better way?


Solution

  • Function.prototype.call is a perfectly solid solution for this sort of situation.

    Calling functions with a different context of this is part of what it's for.

    If you'd like a more elegant but ES5 solution (so newer browsers only) you can use .bind

     $(document).ready(plugin.options.callback.bind(plugin));
    

    Bind sets a function's this value for when you call it (as well as other parameters optionally). Here's an example of how .bind works.

    jQuery shims it with $.proxy if you'd like to use that.

    You can also do

    $(plugin.options.callback.bind(plugin));