views:

249

answers:

3

I need to access this from my setInterval handler

prefs: null,
startup : function()
    {
        // init prefs
        ...
        this.retrieve_rate();
        this.intervalID = setInterval(this.retrieve_rate, this.INTERVAL);
    },

retrieve_rate : function()
    {
        var ajax = null;
        ajax = new XMLHttpRequest();
        ajax.open('GET', 'http://xyz.com', true);
        ajax.onload = function()
        {
            // access prefs here
        }
    }

How can I access this.prefs in ajax.onload ?

A: 

That's not a beauty solution but it's in common usage:

var self = this;
var ajax = null;
//...
ajax.onload = function() {
    self.prefs....;
}
Crozin
The problem is how `setInterval` calls the `retrieve_rate` function, the `this` value inside the method refers to the global object...
CMS
A: 
prefs: null,
startup : function()
    {
        // init prefs
        ...
        this.retrieve_rate();
        var context = this;
        this.intervalID = setInterval(function()
                                      {
                                          context.retrieve_rate();
                                      }, this.INTERVAL);
    },

retrieve_rate : function()
    {
        var ajax = null;
        ajax = new XMLHttpRequest();
        ajax.open('GET', 'http://xyz.com', true);
        var context = this;
        ajax.onload = function()
        {
            // access prefs using context.
            // e.g. context.prefs
        }
    }
Matthew Flaschen
`this` inside the function passed to `setInterval`, will refer to the global object. Did you mean `context.retrieve_rate` instead of `this.retrieve_rate` ?
CMS
Thanks for spotting that, CMS.
Matthew Flaschen
This has evolved in the right direction, don't need the context being passed as parameter though.
AnthonyWJones
@Matthew, AnthonySo how do I access it from onload? Tried this.prefs, but didn't work...
Michael
You're welcome Matthew, by the way, you don't need to use `call`, `context.retrieve_rate()` is enough, since you have a *base object* (`context.`)
CMS
Thanks again, @Anthony and @CMS. :) It's easy to get unnecessarily "clever" when closures are in play.
Matthew Flaschen
Couldn't access it neither with `this` nor with `context`... If you know how exactly, please update the access code.
Michael
+4  A: 

The setInterval line should look like this:-

 this.intervalID = setInterval((function(self) {
    return function() {self.retrieve_rate(); } } )(this),
   this.INTERVAL); 

Edit: The same principle applies to the " onload ". In this case its common for the "outer" code to do little, it just sets up the request an then sends it. In this case the extra overhead an additinal function as in the above code is unnecessary. Your retrieve_rate should look more like this:-

retrieve_rate : function()
{
    var self = this;
    var ajax = new XMLHttpRequest();
    ajax.open('GET', 'http://xyz.com', true);
    ajax.onreadystatechanged= function()
    {
        if (ajax.readyState == 4 && ajax.status == 200)
        {
            // prefs available as self.prefs
        }
    }
    ajax.send(null);
}
AnthonyWJones
I was going to do this initially, but then I remembered this pattern is really most useful for loops.
Matthew Flaschen
@Matthew Flaschen: It just as useful for this scenario as it is for loops.
Andy E
@Anthony: so the trick with `self` is the only option here? can you confirm that the solution by Matthew will not work?
Michael
@Michael: First of all its not a "trick" its just how things work in Javascript. Matthew's answer as it currently stands at time of writing this comment doesn't work. There was an earlier version of it that might have worked but it involved passing `this` as a parameter which was unnecessary and awkard (any caller of `retrieve_rate` would have know this unnecessary special requirement).
AnthonyWJones