James James - 3 months ago 14
Javascript Question

Unable to get property of undefined or null reference - Windows 8 JS/CSS app

Below is a snippet of my code. The error I am getting is that when I perform a search and call the method

_searchData
, it successfully calls the method
_lookUpSuccess
, however then returns the following error:

JavaScript runtime error: Unable to get property '_displayResult' of undefined or null reference

when it tries to call the
_displayResult
method.

Why this may be?

(function () {

// make this an object property/method eventually
var displayResult = function (queryResult) {
for (var i = 0; i < holder.length; i++) {
//document.querySelector(".item-content .title").textContent = "FilmApp";
document.querySelector(holder[i]).textContent = queryResult[i];
}};

// Creates a new page control with members
ui.Pages.define(searchPageURI, {
//...
_searchData: function (queryText) {
searchBase = 'http://www.example.com/web-service2.php?termID=';
searchFormat = 'JSON';
searchFormatPiece = '&format=' + searchFormat;

if (!window.Data) {
var searchUrl = searchBase + queryText + searchFormatPiece;
WinJS.xhr({ url: searchUrl }).done(this._lookUpSuccess, this._lookUpFail, this._lookUpProgress);
}else{
document.querySelector(".titlearea .pagetitle").textContent = "There has been a computer malfunction - sort it the **** out!";
}
},

_lookUpSuccess: function xhrSucceed(Result) {
var response = JSON.parse(Result.responseText);
if (response.response[0].Message === "Found") {
for (var x in response.response[1].term) {
content.push(response.response[1].term[x]);
};
this._displayResult(content);
//displayResult(content);
return content;
} else {
content.push("Not Found", "Not Found");
return content;
}
},

_lookUpFail: function xhrFail(Result) { document.querySelector(".titlearea .pagetitle").textContent = "Got Error"; },
_lookUpProgress: function xhrProgress(Result) { document.querySelector(".titlearea .pagetitle").textContent = "No Result 2"; },

_displayResult: function (queryResult) {
var holder;
holder = [DefDiv, DescDiv];

for (var i = 0; i < holder.length; i++) {
//document.querySelector(".item-content .title").textContent = "FilmApp";
document.querySelector(holder[i]).textContent = queryResult[i];
};
},

});

// End of UI.page.define

// #2 This method is run on application load
WinJS.Application.addEventListener("activated", function (args) {
if (args.detail.kind === appModel.Activation.ActivationKind.search) {
args.setPromise(ui.processAll().then(function () {
if (!nav.location) {
nav.history.current = { location: Application.navigator.home, initialState: {} };
}
return nav.navigate(searchPageURI, { queryText: args.detail.queryText });
}));
}
});

// #3
appModel.Search.SearchPane.getForCurrentView().onquerysubmitted = function (args) { nav.navigate(searchPageURI, args); };

})();

Answer

In this line of code:

WinJS.xhr({ url: searchUrl }).done(this._lookUpSuccess, this._lookUpFail, this._lookUpProgress);

You are passing _lookupSuccess as the done handler function, but when it is called, the value of this is no longer what you want it to be because that will be set by the internals of whatever calls the done handler. Passing this._lookUpSuccess as the function just passes the function. It doesn't pass the value of this. So, when this._lookUpSuccess is called with the wrong this, any references to this inside of it will not find the expected properties on it (thus the error you see).

You can fix it like this which saves the this value in a local variable and then use it when calling _lookUpSuccess():

var self = this;
WinJS.xhr({ url: searchUrl }).done(function(result) {self._lookUpSuccess(result)}, this._lookUpFail, this._lookUpProgress);

This is a very common work-around for reattaching the proper this value in callbacks.