21

I note that it's recommended to use named functions when binding an event handler to a javascript event. How can I do this when my function needs to be passed the this object?

For example, how would I replace the anonymous function below by directly calling doFancyStuff:

$(document).on('change', 'input.fancy-textbox', function () {
    doFancyStuff($(this));
});

function doFancyStuff($textbox) {
    // fanciness
}

Extra points if you point out other conventions I might be breaking with the above code.


To clarify, I want to call the doFancyStuff() method in my example from multiple places, otherwise yes, I could just do something like this:

$(document).on('change', 'input.fancy-textbox', doFancyStuff);

function doFancyStuff() {
    var $textbox = $(this);

    // fanciness
}
Community
  • 1
  • 1
ajbeaven
  • 9,265
  • 13
  • 76
  • 121

5 Answers5

12

I would say that's a matter of opinion. I see no problem using an anonymous function here. If this is the only place doFancyStuff is called, you could do this:

$(document).on('change', 'input.fancy-textbox', doFancyStuff);

function doFancyStuff() {
    // fanciness
    var $textbox = $(this)
}

However, if this function is called from multiple places and you can't change the way it works, you would have to do something like this:

$(document).on('change', 'input.fancy-textbox', doFancyStuffFromEvent);

function doFancyStuffFromEvent() {
    // fanciness
    doFancyStuff($(this));
}

function doFancyStuff($textbox) {
    // fanciness
}

Which is messy.

James Montagne
  • 77,516
  • 14
  • 110
  • 130
  • Unfortunately the function is called from multiple places - some places where `this` is not the the `$textbox` I want the function to have access to. Do you have any suggestions as to how I could change the function to suit what I need better? – ajbeaven Jan 26 '12 at 21:15
  • The 2nd example is the way around this, though I prefer the code you started with that has the anonymous function. Additionally, you could probably use the first and check if the first argument is a jquery object or an event and work differently in each, again I find this messier than the inline function. – James Montagne Jan 26 '12 at 21:15
  • An example of the testing of the first argument to see what type it is: http://jsfiddle.net/Rzsep/ but I'm not putting it in my answer because I don't like it. Note the way I test if it is an event is probably a crappy way to test, but it's just quick and dirty. – James Montagne Jan 26 '12 at 21:20
10

I use $.proxy to solve this issue:

$(document).on('change', 'input.fancy-textbox', $.proxy(doFancyStuff, myChoiceofThis);

function doFancyStuff(event) {

    // $el is the same as $(this) when using anonymous functions
    var $el = $(event.currentTarget); 

    // me === myChoiceOfThis 
    var me = this; // me === myChoiceOfThis
}

If doFancyStuffis an object method, then being able to give a reference such as myChoiceOfThis is very useful.

T. Junghans
  • 11,385
  • 7
  • 52
  • 75
  • 1
    This is a very neat way to do it. You can execute an event handler in the context of any element you pass into the proxy. `var proxy = $.proxy(doFancyStuff, $('.my-other-element'));` `proxy();` – Steven Anderson May 30 '14 at 00:55
  • very nice answer! best and easiest way to do it! – Alphacoder Oct 10 '17 at 16:26
7

Just pass the function as is:

$(document).on('change', 'input.fancy-textbox', doFancyStuff);

function doFancyStuff() {
    $(this).fancy(); // :-P
}

jQuery will automatically invoke your function with the proper context set.


As for other conventions you might be breaking: are you sure you need event delegation? If not, this would be much better:

$('input.fancy-textbox').on('change', doFancyStuff);

or you could even use the short-hand version:

$('input.fancy-textbox').change(doFancyStuff);
Joseph Silber
  • 214,931
  • 59
  • 362
  • 292
4

You will actually be able to use $(this) inside your method doFancyStuff if you define it as your event handler. The .on() method will set the context (this) accordingly:

$(document).on('change', 'input.fancy-textbox', doFancyStuff);

function doFancyStuff() {
    // 'this' will be the changed input.fancy-textbox
}
Didier Ghys
  • 30,396
  • 9
  • 75
  • 81
2

You have to change doFancyStuff to expect the same signature as your anonymous function. The way you've coded this, it looks like it expects a single parameter of a jQuery object, and ignores "this." But the parameter of an event is something else (the event object) and "this" is the target. If you want to use a function as an event target, then it's got to expect the same data. So rewrite:

$(document).on('change', 'input.fancy-textbox', doFancyStuff);

function doFancyStuff(e) {
    var $textbox = $(this);       
    // fanciness
} 
Jamie Treworgy
  • 23,934
  • 8
  • 76
  • 119