views:

78

answers:

4

Hi there, I'm a newbee about jQuery's workflow and I would like to setup a javascript class that uses an internal method to make an AJAX request. When the request returns with success, the jQuery AJAX callback should invoke a method owned by the class itself. That's the code:

function IXClock()
{
    this.m_intervalID = 0;

    this.startClock = function ()
    {
        this.m_intervalID = setInterval(this.tictac, 500);
    }

    this.stopClock = function ()
    {
        clearInterval(this.m_intervalID);
    }

    this.setClockTime = function(p_strTime)
    {
        $('#clock').html(p_strTime);
    }

    this.tictac = function ()
    {
        $.ajax
        ({
                type: 'POST',
                url: '/rap/rapClock.php',
                complete: function (data)
                {
                    this.setClockTime(data);
                }
        });
    }

}

The class represents a clock, with an internal method (tictac) that requests "what's the time" on the server side. After the server says the time, the jQuery's AJAX method should invoke the setClockTime method of the IXClock class. The invoke method will update the #clock div item in the html page.

The problem is that the method this.setClockTime() results unknown and the javascript return the "this.setClockTime is not a function" error.

The question is: is there a way to invoka a class method from the jQuery's AJAX callback ?

+1  A: 

I think that the problem is that the this in your callback function is different from the this referring to IXClock. Try:

var thisClass = this ;
this.tictac = function ()
{
    $.ajax
    ({
            type: 'POST',
            url: '/rap/rapClock.php',
            complete: function (data)
            {
                thisClass.setClockTime(data);
            }
    });
}

Test Case (added to site which already has jQuery loaded):

function uClass () {
    this.testFunction = function(input) {
        alert(input) ;
    }
    this.ajaxFunction = function() {
        var myClass = this ;
        $.ajax({
            type: 'POST',
            url: '/',
            complete: function(data) {
                alert(myClass.testFunction) ;
                myClass.testFunction(data) ;
                this.testFunction(data) ;
            }
        }) ;
    }
}

var k = new uClass() ;
k.ajaxFunction() ;
Gus
+1 Probably the easiest of the proposed solutions.
Kristoffer S Hansen
Seems like the perfect solution, but I get the same error: thisClass.setClockTime is not a function
iakko
Hi, I have added a test case to my answer which should demonstrate the solution and the error you experienced. Does this work for you? If not, can you provide more detail of how you are using `IXClock`, and what version of jQuery you are running?
Gus
It's exactly like yours. Seems strange, here is mine: http://iakko.net/jquery-ajax
iakko
Ah - because the `tictac()` function is being called by `window.setInterval`, the `this` that you are setting to `myClass` is the `window` object. You will need to move the line `var myClass = this ;` into the `IXClock()` definition, just above the line `this.tictac = function()`. Sorry.
Gus
Well, that's the same thing again! If I put myClass outside tictac, how should I reference to myClass from inside the AJAX callback? Take a look to the same url: http://iakko.net/jquery-ajax . The same error again! Am I missing something ?
iakko
Instead of `this.myClass = this;`, it should be `var myClass = this;` and instead of `this.myClass.setClockTime(data);`, you can call the variable myClass directly: `myClass.setClockTime(data);`. This works because variables declared with `var` are made available by javascript to all functions declared within the same scope, plus functions in any descendent scopes.
Gus
Ok, now it's working :)I need to know something: you say that with var myClass = this; javascript shows the same value for al the function inside IXClock. As far as I know, this.myClass declares a 'member' of the class, that should be the same thing! Can you explaine me the differents more deeply ? If you prefere, you can point me in some tutorial where all this is already explained!Anyway, thanks :)
iakko
You're welcome. The issue with `this.myClass`, is that you still need a handle to `this` in order to access it. Within your ajax callback function, `this` has changed (at least) twice, firstly to refer to the `window` object after the `window.setInterval()` call, and then to refer to jQuery's xmlHttpRequest wrapper object, which is the object which calls your callback function.
Gus
Ok, re-reading everything, I figured out the entire issue now!Thank you very much! :)
iakko
A: 

this does not refer to IXClock in your ajax callback. this allways points to the current scope (have a look at this document). You need to do something like this:

this.prototype.tictac = function ()
{
    var self = this;
    $.ajax
    ({
        type: 'POST',
        url: '/rap/rapClock.php',
        complete: function (data)
        {
            self.setClockTime(data);
        }
    });
}

You can also use jQuery's .proxy()-function for this purpose:

this.prototype.tictac = function ()
{
    $.ajax
    ({
        type: 'POST',
        url: '/rap/rapClock.php',
        complete: $.proxy(function (data) {
            this.setClockTime(data);
        }, this)
    });
}
elusive
Why has this been downvoted again? If you do not like my answer, tell me why! I do not see any errors here.
elusive
A: 

The this in the result handler is not what you expect it is. (It is not the IXClock instance)

function IXClock()
{
    this.m_intervalID = 0;
}

IXClock.prototype = {

    startClock: function ()
    {
        this.m_intervalID = setInterval(this.tictac, 500);
    },

    stopClock: function ()
    {
        clearInterval(this.m_intervalID);
    },

    setClockTime: function(p_strTime)
    {
        $('#clock').html(p_strTime);
    },

    tictac: function ()
    {
        var that = this;
        $.ajax({
            type: 'POST',
            url: '/rap/rapClock.php',
            success: function (data) { // You want success here, not complete, IMO
                that.setClockTime(data);
            }
        });
    }

}

If you ask me, that ajax call is doing evil. It does not seem to send any data, nor modify any state on the server, but is expecting/getting/using data from the php, yet is using the POST method. Should've been

$.get('/rap/rapClock.php', function (data) {
    that.setClockTime(data);
});
Shrikant Sharat
A: 

Hello. It happens bacause your callback function leave in global context.

You can choose 2 ways

  1. Use .bind function to bind context to callback function http://www.robertsosinski.com/2009/04/28/binding-scope-in-javascript/

  2. jQuery's AJAX supports transfer some data to callback function. You can write smth like this:

:

this.tictac = function () { $.ajax ({ type: 'POST', context:this, url: '/rap/rapClock.php', complete: function (data) { this.setClockTime(data); } }); }

}
Falcon
Unfortunately, that doesn't work.
iakko