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?

1
  • Dunno why you're trying to make jQuery OO since jQuery is more functional than OO. Commented Feb 6, 2009 at 11:51

8 Answers 8

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));
Sign up to request clarification or add additional context in comments.

Comments

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.

4 Comments

this is in fact very useful, the best approach I've seen so far.. thanks dude!
Neat solution. I love it.
YOu 're clever like me :-D
This is the best. No additional complicated closure code. Thanks
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

Comments

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"

5 Comments

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.
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.
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?
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: 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.
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));

Comments

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));

4 Comments

Alas this seems to be only in JS 1.8.5, and this cuts out browsers such as IE8.
@LukeH bind method is just some js code.. developer.mozilla.org/en-US/docs/JavaScript/Reference/…
@JLRishe you can use this polyfill for IE8
@Orlando You are indeed correct. I'm going to delete my earlier comment now.
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.

Comments

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
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.