0

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?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Tom Auger
  • 19,421
  • 22
  • 81
  • 104

1 Answers1

1

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));
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • Very reassuring! Thanks. Can you show me what the call would be like using jQuery's proxy? I had thought that might be the way, but got discouraged by the syntax - I was under the impression I would be setting the context for ALL calls to ready() (as opposed to all calls to my callback) – Tom Auger May 21 '13 at 20:28
  • Hmm, I think so. So my line would become: `$( document ).ready( $.proxy( plugin.options.callback, plugin )() )`? I kind of prefer `bind()`, but will that leave IE7-9 users in the dust? – Tom Auger May 23 '13 at 16:39
  • I prefer bind to. Id prefer people not use IE7-9 either :) Sadly, proxy would have to do. If you feel your issue is solved please consider accepting this answer. – Benjamin Gruenbaum May 23 '13 at 16:40