views:

173

answers:

5

I have a function which is a JQuery event handler. Because it is a JQuery event handler, it uses the this variable to refer to the object on which it is invoked (as is normal for that library).

Unfortunately, I need to manually call that method at this point. How do I make this inside the called function behave as if it were called from JQuery?

Example code:

function performAjaxRequest() {
    //Function which builds AJAX request in terms of "this"
}

function buildForm(dialogOfForm) {
    var inputItem;
    dialogOfForm.html('...');
    dialogOfForm.dialog('option', 'buttons', {
        "Ok" : performAjaxRequest
    });
    inputItem = dialogOfForm.children(':not(label)');
    //Redirect enter to submit the form
    inputItem.keypress(function (e) {
        if (e.which === 13) {
            performAjaxRequest(); //Note that 'this' isn't the dialog box
                                  //as performAjaxRequest expects here, it's
                                  //the input element where the user pressed
                                  //enter!
        }
    }
}
+7  A: 

If dialog is the object that you need to be set to this then:

performAjaxRequest.apply(dialog, []); 
// arguments (instead of []) might be even better

should do the trick.

Otherwise, in jQuery you can simply call the trigger method on the element that you want to have set to this

Say, for example, that you wanted to have a click event happen on a button and you need it to happen now. Simply call:

$("#my_button").trigger("click");

Your #my_button's click handler will be invoked, and this will be set to the #my_button element.

If you need to call a method with a different this ... say for example, with this referring to the jQuery object itself, then you will want to use call or apply on your function.

Chuck and meder have already given you examples of each ... but to have everything all in one place:

// Call
my_function.call(object_to_use_for_this, argument1, argument2, ... argumentN);

// Apply
my_function.apply(object_to_use_for_this, arguments_array);

SEE: A List Apart's Get Out of Binding Situations

Sean Vieira
Let's say I don't have a handy reference to the actual event or element on which the event would be fired.
Billy ONeal
@Billy ... so you want to trigger a variable event on a variable object or set of objects? If so, what does the general code look like? What *do* you know at the moment you want to trigger whatever it is you need to trigger?
Sean Vieira
@Sean: Just updated the question -- let me know if that makes it clearer.
Billy ONeal
@Billy -- and I just updated my answer ... does that help?
Sean Vieira
@Sean: Yes. +1 to you :)
Billy ONeal
+9  A: 

You can use the function's call method.

someFunction.call(objectToBeThis, argument1, argument2, andSoOnAndSoOn);
Chuck
+1 to the first answer that answers the most direct problem I posed. Checkmarked @Sean's answer though simply because it's more complete.
Billy ONeal
+3  A: 

Are you looking for..

functionRef.apply( objectContext, arguments);
meder
+1 -- Also a good answer, though @Chuck's answer more directly does what I was looking for.
Billy ONeal
A: 

use a closure i.e assign this to that early on; then you can do what you like with it.

var that = this;
dryprogrammers
Look at my example code. Note that the <s>event</s>function is being called from two places. How do you propose solving that with a closure without duplicating the content of `performAjaxRequest` ?
Billy ONeal
+1  A: 

You should of course learn to master call() and apply() as people have stated but a little helper never hurts...

In jQuery, there is $.proxy. In pure js, you can re-create that niftyness ;) with something like:

function proxyFn( fn , scope ){
  return function(){
     return fn.apply(scope,arguments);
  }
}

Usage Examples:

var myFunctionThatUsesThis = function(A,B){
  console.log(this,arguments); // {foo:'bar'},'a','b'
};

// setTimeout or do Ajax call or whatever you suppose loses "this"

var thisTarget = {foo: 'bar'};
setTimeout( proxyFn( myFunctionThatUsesThis, thisTarget) , 1000 , 'a', 'b' );

// or...

var contextForcedCallback = proxyFn( myAjaxCallback , someObjectToBeThis );
performAjaxRequest(myURL, someArgs, contextForcedCallback );

If you dont abuse it, it's a sure-fire tool to never loose the scope of "this".

Quickredfox
Sorry, the original function I provided contained a mental lapsus. It has ben updated to the correct version.
Quickredfox