views:

81

answers:

4

Note: This question uses jQuery but the question has nothing to do with jQuery!

Okay so I have this object:

var box = new BigBox();

This object has a method named Serialize():

box.AddToPage();

Here is the method AddToPage():

function AddToPage()
{
    $('#some_item').html("<div id='box' onclick='this.OnClick()'></div>");
}

The problem above is the this.OnClick() (which obviously does not work). I need the onclick handler to invoke a member of the BigBox class. How can I do this?

How can an object refer to itself in an event handler?

+1  A: 

Don't add event handlers with inline code.

function AddToPage()
{
    $('#some_item').html("<div id='box'></div>");
    $('#box').click(this.OnClick);
}

EDIT:

Another way (avoids the extra select):

function AddToPage()
{
    var div = $('<div id="box"></div>'); // probably don't need ID anymore..
    div.click(this.OnClick);

    $('#some_item').append(div);
}

EDIT (in response to "how to pass parameters");

I'm not sure what params you want to pass, but..

function AddToPage()
{
    var self = this, div = $('<div></div>');
    div.click(function (eventObj) {
        self.OnClick(eventObj, your, params, here);
    });

    $('#some_item').append(div);
}
Matt
Ah. I see that this is probably a better option anyway considering the structure of the rest of the code. Thanks :)
George Edison
This will not work.
SLaks
That doesn't help at all.
T.J. Crowder
Oh. And also, how do you pass parameters to the `OnClick` handler?
George Edison
@SLaks: Why not?
George Edison
@George: `OnClick` will not be called in context. See my answer.
SLaks
And your edit doesn't help. There's nothing in `div.click(this.OnClick);` that will preserve `this` (even if `this` is right when you call it, which is far from certain).
T.J. Crowder
@T.J. you're mistaken, `this` is the correct context during the ASSIGNMENT of the click handler. What you're talking about is referencing `this` during the EXECUTION of the handling function.
Matt
@Matt: No, I'm not mistaken, and your further edit continues to completely miss the point. He wants to call an event handler where, within the event handler, `this` refers to an instance of `BigBox`. It's perfectly clear from his question. None of your three tries at an answer so far has addressed that. SLaks' answer is the first that does. http://stackoverflow.com/questions/2694616/how-to-refer-to-object-in-javascript-event-handler/2694655#2694655
T.J. Crowder
Okay, finally you have a version that actually works, although you seem to think that it relates to parameters (it doesn't). Upvoting SLaks.
T.J. Crowder
@T.J. the third edit is actually the same functionality as SLaks, except I pass the event object around. So you must be misreading.
Matt
@T.J. and for your future reference, passing a function handler from `this` during ASSIGNMENT will not break, regardless of context. It would only break if the *handling function* referenced `this` during execution.
Matt
What's there now does (third edit). If that was there before, sorry. The "parameters" irrelevancy threw me. The main issue was `self`.
T.J. Crowder
@Matt: The issue I've been banging on about is what `this` means *within the call to the function*. Your third (labelled) edit gets it right, your first two do not. Just passing `this.OnClick` as the handler function will not set it up correctly.
T.J. Crowder
@T.J. if OP didn't want to pass special parameters (which I didn't initially realize), `this.OnClick` would work fine. It would pass to jQuery a function reference that points to the current `this.OnClick` .. even if context changes, jQuery will be calling the original function referenced. That's why I only bothered with `self` during the parameter example, because it wasn't needed for the first two to work.
Matt
T.J. Crowder
@T.J., @Matt - I still can't get it to work. `OnClick` doesn't seem to be getting called within the context of `this`. If I do the following: (using above example) `div.click(function() { this.OnClick(); });` it doesn't work.
George Edison
@T.J. - mea culpa. You are correct that any references to the object within the handler will be bound to the jQuery element, not the BigBox object. My little test missed that important element since I was just doing an alert. I had assumed you meant that it wouldn't bind the correct handler, not that it wouldn't bind the handler correctly. :-)
tvanfosson
@George: Refer to SLaks' and James' answers (although as Matt points out, his answer now does this as well). Fundamentally, functions in Javascript are just functions, unlike other languages `this` is determined *entirely* by how the function is called, not where it's defined. This can be counter-intuitive (but also powerful). FWIW, check out the posts I point tvanfosson at above.
T.J. Crowder
@tvanfosson: It's a really, really easy mistake to make. :-) (Nice wordplay, btw! I love that kind of thing.)
T.J. Crowder
@T.J. - I finally figured it out. Thanks. Apparently I was getting an error and I thought it was related to this. :)
George Edison
+1  A: 

If you are using jQuery, then you can separate your code from your markup (the old seperation of concerns thing) like this

$(document).ready(function() {

  var box = new BigBox();

  $('#box').click(function() {
    box.serialize();
  });

});

You only need to add the click handler once for all divs with id of box. And because the click is an anonymous function, it gets the scope of the function it is placed in and therefore access to the box instance.

James Westgate
That does nothing to address his question about ensuring that `this` relates to an instance of `BigBox` (are people just not reading the question?).
T.J. Crowder
Fair point, I forgot to include that once I started the reply.
James Westgate
@James: Nice, clear fix. :-)
T.J. Crowder
+4  A: 

You should attach the handler using jQuery:

function AddToPage()
{
    var self = this;
    $('#some_item').empty().append(
        $("<div id='box'></div>")
            .click(function() { self.OnClick(someParameter); })
    );
}

In order to force the event handler to be called on the context of your object (and to pass parameters), you need to add an anonymous function that calls the handler correctly. Otherwise, the this keyword in the handler will refer to the DOM element.

SLaks
+1  A: 

In jQuery 1.4 you could use a proxy.

BigBox.prototype.AddToPage= function () {
    var div= $('<div>', {id: box});
    div.click(jQuery.proxy(this, 'OnClick');
    div.appendTo('#some_item');
}

You can also use a manual closure:

    var that= this;
    div.click(function(event) { that.OnClick(event); });

Or, most simply of all, but requiring some help to implement in browsers that don't yet support it (it's an ECMAScript Fifth Edition feature):

    div.click(this.OnClick.bind(this));
bobince