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?
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
});
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With