74

I have created a 'control' using jQuery and used jQuery.extend to assist in making it as OO as possible.

During the initialisation of my control I wire up various click events like so

jQuery('#available input', 
            this.controlDiv).bind('click', this, this.availableCategoryClick);

Notice that I am pasing 'this' as the data argument in the bind method. I do this so that I can get at data attached to the control instance rather from the element that fires the click event.

This works perfectly, however i suspect there is a better way

Having used Prototype in the past, I remember a bind syntax that allowed you to control what the value of 'this' was in the event.

What is the jQuery way?

pb2q
  • 58,613
  • 19
  • 146
  • 147
Pat Long - Munkii Yebee
  • 3,592
  • 2
  • 34
  • 68

8 Answers8

104

You can use jQuery.proxy() with anonymous function, just a little awkward that 'context' is the second parameter.

 $("#button").click($.proxy(function () {
     //use original 'this'
 },this));
Antti29
  • 2,953
  • 12
  • 34
  • 36
Torbjörn Nomell
  • 3,020
  • 2
  • 24
  • 20
39

I like your way, in fact use a similar construction:

$('#available_input').bind('click', {self:this}, this.onClick);

and the first line of this.onClick:

var self = event.data.self;

I like this way because then you get both the element clicked (as this) and the "this" object as self without having to use closures.

davidfurber
  • 5,274
  • 1
  • 20
  • 11
33

jQuery has the jQuery.proxy method (available since 1.4).

Example:

var Foo = {
  name: "foo",

  test: function() {
    alert(this.name)
  }
}

$("#test").click($.proxy(Foo.test, Foo))
// "foo" alerted
benpickles
  • 1,560
  • 1
  • 16
  • 24
21

I don't think jQuery has a built-in feature for that. But you could use a helper construct like the following:

Function.prototype.createDelegate = function(scope) {
    var fn = this;
    return function() {
        // Forward to the original function using 'scope' as 'this'.
        return fn.apply(scope, arguments);
    }
}

// Then:
$(...).bind(..., obj.method.createDelegate(obj));

This way, you can create dynamic 'wrapper functions' with createDelegate() that call the method with a given object as its 'this' scope.

Example:

function foo() {
    alert(this);
}

var myfoo = foo.createDelegate("foobar");
myfoo(); // calls foo() with this = "foobar"
Ferdinand Beyer
  • 64,979
  • 15
  • 154
  • 145
  • 40
    Guys, this post was written in Feb 2009, at this time there was no `jQuery.proxy()` yet (appeared in v.1.4, Jan 2010). No need to downvote. – Ferdinand Beyer Nov 22 '11 at 15:36
  • 5
    Isn't it about giving the best answers the most votes? I appreciate if outdated answers get down-voted or removed. It helps avoiding misguidance IMHO. – ben May 30 '14 at 20:56
  • 1
    Of course the best answer should get most votes, as it is the case here. But this does not mean that second-best answers should be down-voted. That decreases reputation and is simply not fair. What do you expect me to do? Check and revise my ancient answers on a regular basis? – Ferdinand Beyer May 31 '14 at 06:47
  • 1
    No. I do by no means claim you did anything wrong. IMHO this scenario is just not covered well by the mechanisms of SO (at least AFAIK). Answers which were very suitable at one point got upvoted and stay there even if they are developing unsuitable over time because other methods came up which outperform the old mechanisms. IMHO it would be best if it would be possible to flag these answers such that either the author gets notified and may react or that some indication is given that the answer might be outdated. – ben May 31 '14 at 11:13
  • 4
    @ben: Answers may be outdated, but that's no reason to deprive the author of the credit they earned when the answers were relevant. I think suggesting a flag feature for outdated answers is better than down-voting what was once the correct answer. – Mike Purcell May 21 '15 at 19:50
5

HTML 5-compliant browsers provide a bind method on Function.prototype which is, probably the cleanest syntax and is not framework-dependent, though it is not built into IE until IE 9. (There is a polyfill for browsers without it, though.)

Based on your example, you can use it like this:

jQuery('#available input', 
        this.controlDiv).bind('click', this.availableCategoryClick.bind(this));

(side note: the first bind in this statement is part of jQuery and has nothing to do with Function.prototype.bind)

Or to use slightly more concise and up-to-date jQuery (and eliminate confusion from two different kinds of binds):

$('#available input', this.controlDiv).click(this.availableCategoryClick.bind(this));
JLRishe
  • 99,490
  • 19
  • 131
  • 169
4

you can use the javascript bind method like this:

var coolFunction = function(){
  // here whatever involving this
     alert(this.coolValue);
}

var object = {coolValue: "bla"};


$("#bla").bind('click', coolFunction.bind(object));
Orlando
  • 9,374
  • 3
  • 56
  • 53
  • Alas this seems to be only in JS 1.8.5, and this cuts out browsers such as IE8. – Luke H May 05 '13 at 20:15
  • 1
    @LukeH bind method is just some js code.. https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind – Orlando May 06 '13 at 03:49
  • 1
    @JLRishe you can use this [polyfill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility) for IE8 – Orlando Apr 24 '14 at 18:43
  • @Orlando You are indeed correct. I'm going to delete my earlier comment now. – JLRishe Dec 13 '14 at 20:13
2

jQuery does not support binds and the preferred way is to use functions.

Because in Javascript, this.availableCategoryClick does not mean calling the availableCategoryClick function on this object, jQuery advise to use this preferred syntax:

var self = this;
jQuery('#available input', self.controlDiv).bind('click', function(event)
{
   self.availableCategoryClick(event);
});

OO concepts in Javascript are hard to understand, functionnal programming is often easier and more readable.

Vincent Robert
  • 35,564
  • 14
  • 82
  • 119
1

Seeing that functions changes scope, the most common way is to do it by hand, with something like var self = this.

var self = this

$('.some_selector').each(function(){
  // refer to 'self' here
}
August Lilleaas
  • 54,010
  • 13
  • 102
  • 111