Search code examples
javascriptwindows-8

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); };

})();

Solution

  • 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.