1

If I am using this code why has the scope changed for the "doStuff" alert? Is there a way that I can make sure that the scope is my object and not the Window object?

Here is the same code in jsfiddle.

(function ($) {
    var c$ = {};

    c$.TestScope = function () {

        this.doAjax = function (onComplete) {
            var self = this;
            $.ajax({
                url: 'badurl',
                complete: function (data) {
                    alert('doAjax2 self === c$.oTestScope: ' + (self === c$.oTestScope).toString());
                    onComplete(data);
                }
            });
            alert('doAjax1 self === c$.oTestScope: ' + (self === c$.oTestScope).toString());  
        };

        this.doStuff = function (data) {
            var self = this;
            alert('doStuff self === c$.oTestScope: ' + (self === c$.oTestScope).toString());
        }

    };

    c$.oTestScope = new c$.TestScope();
    c$.oTestScope.doAjax(c$.oTestScope.doStuff);
})(jQuery);​

2 Answers 2

5

You should be able to specify the this value as the context in your $.ajax() parameters:

var c$ = {};

c$.TestScope = function() {

    this.doAjax = function(onComplete) {

        alert('doAjax1 this === c$.oTestScope: ' + (this === c$.oTestScope).toString());

        $.ajax({
            url: 'badurl',
            context: this,
            complete: function(data) {
                alert('doAjax2 this === c$.oTestScope: ' + (this === c$.oTestScope).toString());
                onComplete.call(this, data);
            }
        });
    };

    this.doStuff = function(data) {
        alert('doStuff this === c$.oTestScope: ' + (this === c$.oTestScope).toString());
    }

};

c$.oTestScope = new c$.TestScope();
c$.oTestScope.doAjax(c$.oTestScope.doStuff);

Edit I made a fiddle for this and verified that it works properly. There's no messing around with an extra self parameter or having to muck around with closures to keep your variables.

Part of what you were missing was calling onComplete.call(this, data) to invoke doStuff().

5
  • The context option only seems to work when you call the function directly "context:onComplete". I can't see any way that you can have default functionality as well as callback functionality using this method. Here is that jsfiddle with the context option jsfiddle.net/RW4Ge/2.
    – bconrad
    Commented Nov 2, 2012 at 16:51
  • I know you've already chosen your solution, but please give this revision a look. It cleanly fixes your problem with this without having to use any extra closures or temporary variables. Commented Nov 2, 2012 at 21:43
  • I appreciate your help and maybe I am missing something but your example isn't using the onComplete callback. It is calling doStuff directly. If you change this.doStuff(data) to onComplete(data), (this === c$.oTestScope) will return false. I agree that your syntax is much cleaner. If I can get it to work I'll use it.
    – bconrad
    Commented Nov 3, 2012 at 17:33
  • If you need to use the passed-in function, then you want to use onComplete.call(this, data); That is the same as this.doStuff(), except that you can use the passed-in function no matter what it is. Commented Nov 3, 2012 at 17:41
  • 1
    Perfect. That does it. Thanks for sticking with me.
    – bconrad
    Commented Nov 3, 2012 at 20:07
3

I have altered your code to pass a reference to this onto the doStuff() code.

(function ($) {
    var c$ = {};

    c$.TestScope = function () {

        this.doAjax = function (onComplete) {
            var self = this;
            $.ajax({
                url: 'badurl',
                complete: function (data) {
                    alert('doAjax2 self === c$.oTestScope: ' + (self === c$.oTestScope).toString());
                    onComplete(data,self);
                }
            });
            alert('doAjax1 self === c$.oTestScope: ' + (self === c$.oTestScope).toString());  
        };

        this.doStuff = function (data,thisRef) {
            var self = thisRef;
            alert('doStuff self === c$.oTestScope: ' + (self === c$.oTestScope).toString());
        }

    };

    c$.oTestScope = new c$.TestScope();
    c$.oTestScope.doAjax(c$.oTestScope.doStuff);
})(jQuery);​
1
  • 1
    That is good. The only problem I had with it is that I would always have to add the "thisRef" parameter to "doStuff". I got around this by added that as an optional parameter and setting "self" to "this" if that option was not provided. Here is my updated jsfiddle jsfiddle.net/RW4Ge/3.
    – bconrad
    Commented Nov 2, 2012 at 16:55

Not the answer you're looking for? Browse other questions tagged or ask your own question.