Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript interpretation of "this" keyword within $.ajax()

I realize that the TypeScript compiler is attempting to stay true to plain old JavaScript, as TypeScript is indeed JavaScript. However, there is a disconnect between what Intellisense interprets as the "this" keyword and what it actually resolves to during runtime. For example, consider the following TypeScript ajax call:

 getAgencies() {
            var self = this;          
            $.ajax(liveString + "/Home/GetSupportedAgencies",
            {
                type: "GET",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                error: Utilities.Logger.displayAjaxError,
                success: this.onGetAgenciesComplete
            });

        }

and its corresponding callback:

   onGetAgenciesComplete(agencies) {
                var self = this;
                    if (agencies == null)
                        Utilities.Logger.displayErrorOnLogConsole("There was an error retrieving supported agencies.  Refresh site and try again.");
                    else {
                        $.each(agencies, function (i, a) {
                            self._indexViewModel.agencies.push({ name: a.Name, fullName: a.FullName, shortName: a.ShortName, bbox: a.BBox, countryCode: a.CountryCode });
                        });

                        if (Modernizr.geolocation) {
                            navigator.geolocation.getCurrentPosition(
                                function (position) {
                                    self.initMapPage(position, self);
                                },
                                function (error) {
                                    Utilities.Logger.displayErrorOnLogConsole("Oops, we could not get your location at his time. Please try later.");
                                });
                        }
                        else {
                            Utilities.Logger.displayErrorOnLogConsole("Sorry, your browser does not return location information.");
                            self.getBusRoutes(self.agencyName);
                        }


                        // end of initialization
                    }
                }

Now, when I hover over line "var self = this" in onGetAgenciesComplete within the TypeScript source file, the Intellisense definition of variable "self" indicates it is of type HomePageViewModelBase, where HomePageViewModelBase is the class that contain the above methods.

The generated Javascript for aforementioned is as follows:

HomePageViewModelBase.prototype.getAgencies = function () {
            var self = this;
            $.ajax(liveString + "/Home/GetSupportedAgencies", {
                type: "GET",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                error: Utilities.Logger.displayAjaxError,
                success: this.onGetAgenciesComplete
            });
        };
        HomePageViewModelBase.prototype.onGetAgenciesComplete = function (agencies) {
            var self = this;
            if(agencies == null) {
                Utilities.Logger.displayErrorOnLogConsole("There was an error retrieving supported agencies.  Refresh site and try again.");
            } else {
                $.each(agencies, function (i, a) {
                    self._indexViewModel.agencies.push({
                        name: a.Name,
                        fullName: a.FullName,
                        shortName: a.ShortName,
                        bbox: a.BBox,
                        countryCode: a.CountryCode
                    });
                });
                if(Modernizr.geolocation) {
                    navigator.geolocation.getCurrentPosition(function (position) {
                        self.initMapPage(position, self);
                    }, function (error) {
                        Utilities.Logger.displayErrorOnLogConsole("Oops, we could not get your location at his time. Please try later.");
                    });
                } else {
                    Utilities.Logger.displayErrorOnLogConsole("Sorry, your browser does not return location information.");
                    self.getBusRoutes(self.agencyName);
                }
            }
        };

which when executed variable "self" in HomePageViewModelBase.prototype.onGetAgenciesComplete is resolved to what looks like an AjaxContext and not an instance of HomePageViewModelBase. Is this expected behavior or should I report this as a bug?

like image 747
Klaus Nji Avatar asked Oct 31 '12 13:10

Klaus Nji


2 Answers

Yes you should probably report it to them as a bug, because the this within an $.ajax() is meant to refer to the $.ajax() object itself.

If you want to go around it so that it works, change your success function to:

success: self.onGetAgenciesComplete

Or if you want the this to stand for your class, simply use the context method of $.ajax

$.ajax({ 
    context: this,
    // now *this* will come from the previous scope,
    // which in your case, is your class "HomePageViewModelBase"

    // now that we know for certain what -this- refers to
    success: this.onGetAgenciesComplete
});
like image 186
Mark Pieszak - Trilon.io Avatar answered Oct 01 '22 09:10

Mark Pieszak - Trilon.io


As far as any (including Intellisense) static analysis is concerned, the context of onGetAgenciesComplete is HomePageViewModelBase and always will be; except that at runtime, the context will be set dynamically, via explicit internal jQuery.ajax context binding. The only way Intellisense could determine that the context will change dynamically is to actually execute that code path, but even that results in ambiguity: which context is the right context?

What if you "borrow" a method elsewhere, for a one-off call? Should Intellisense then use that call site to determine the context? Probably not...

HomePage.prototype.onGetAgencies.call({ some other context }, ...);

(Shortened for readability.)

like image 38
Rick Avatar answered Oct 01 '22 09:10

Rick