views:

48

answers:

2

I'm not a Javascript person normally, but I've been diving in, reading Douglas Crockford's book, and writing some trivial, useful tidbits as Chrome extensions and Node.js (note that this question isn't about either of them).

Right now, I'm trying to figure out how to retain a reference to an object that's initiating an AJAX request, that is: once I set the onload event handler (this is from inside a Chrome extension, so I'm using the base XMLHttpRequest object), is there any way that I can refer back to MyObject in the following example:

MyObject.prototype = {
    PerformAction: function() {
        this.Request = new XMLHttpRequest();
        this.Request.open("GET", this.ConstructUrl(), true);
        // From within ActionResultHandler, 'this' will always be the XMLHttpRequest
        this.Request.onload = this.ActionResultHandler,
        this.Request.send(null);
    }
}

Doing this exactly is going to assign this to be the request object itself, and if I simply introduce a wrapper:

this.Request.onload = function() { ActionResultHandler() };

well, that just isn't going to do anything, because the ActionResultHandler is now out of scope. The reason I'm asking here is because I've only found trivial cases of caller manipulation (e.g. manipulating what this refers to from inside a function), but given that OO-ified Javascript and AJAX are literally everywhere, this has to have to be a known, simple issue, but my Google-fu is failing me here. In C#, events are invoked in the context of whoever attaches to them, not the object firing the event, so this doesn't come up on a daily basis. Perhaps there's a much better JS pattern that avoids this issue entirely?

+1  A: 

Have you tried...

this.Request.onload = this.ActionResultHandler.apply(this);

I'm thinking that's what you're looking for (sorry if it's not). Using .apply(this) will point ActionResultHandler to Object.

Check out this article on binding while you're at it! It helped me out a lot.

bschaeffer
Your snippet actually sets `this.Request.onload` to be equal to the return value of `this.ActionResultHandler` called in the context of `this`. I don't think that's what he's trying to accomplish.
lawnsea
Good point, I don't know what I was thinking...
bschaeffer
AFAIK, `this.ActionResultHandler` would always be bound using the present value of `this`..nevertheless, it was on the right track, and the link did help, thanks!
Marc Bollinger
+2  A: 

It's not really clear to me which variable you want to hold a reference to. Here's how you would retain a reference to MyObject in your onload handler:

MyObject.prototype = {
    PerformAction: function() {
        var MyObjectRef = MyObject,
            ActionResultHandler = this.ActionResultHandler;

        this.Request = new XMLHttpRequest();
        this.Request.open("GET", this.ConstructUrl(), true);
        // From within ActionResultHandler, 'this' will always be the XMLHttpRequest
        this.Request.onload = function () {
                ActionResultHandler.apply(MyObjectRef, arguments);
            };
        this.Request.send(null);
    }
}

Edited

Ok, I reread your question again and it seems that you want to execute ActionResultHandler in the context of MyObject, so I tweaked my code to do this.

lawnsea
Indeed that is what I wanted--I settled on assigning the handler this way: `this.Request.onload = function (event) { responder.apply(selfReference, [event, this]); },` in order to preserve both the `XMLHttpRequestProgressEvent` and the `XMLHttpRequest`. Thanks!
Marc Bollinger