'How to pass api data from one method to another within an object?

I made a simple oject called 'weather' that has method inside. The weather object should have three methods.

  1. getWeather: Get weather data which is getWeather method which uses xmlhttprequest api to pull weather info and pass the weatherdata which is xhr.responseText to another method (callback) so that in the second method, I can destructure the weather data and save them to variables.

  2. callback: Like explained, the callback method should get data from the getWeather method. However, i get an error saying "uncaught TypeError: callBack is not a function at XMLHttpRequest.xhr.onload".

  3. search is there to pass the function to the getWeather method when the eventListener is fired when clicked.

In summary, I just want to extract data from the getWeather method and pass that data to the callback

I want to do this without fetch.then or without promisifying my xmlhttprequest.

let weather = {

apiKey:'dcaa6d5ea6bc87524fd5e38257edabba',
city: 'montreal',   

getWeather: function (city, callBack) {
    const xhr = new XMLHttpRequest();
    xhr.open(
        'get'
        ,`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${this.apiKey}`
        , true)
    
        xhr.onload = function () {
        if (xhr.status >= 200 && xhr.status < 300) {
            const weatherData = JSON.parse(xhr.responseText);  
            // console.log(weatherData);
            console.log(weatherData);
            callBack()
        }
        
    }
    xhr.send()
},

callback: function () {
    console.log('weatherData')
},

search: function () {
    this.getWeather('new york')
}
    

};

document
.querySelector('.button')
.addEventListener('click', () => weather.search())


Solution 1:[1]

The error is caused because the JavaScript engine cannot resolve what the value of the callback parameter of getWeather is when it is invoked in weather.search and also when the function you assigned to xhr.onload is eventually invoked when the request completes successfully.

There are several ways you can make sure the callback parameter or variable successfully resolves to the callback method of the weather object, which appears to be what you intended.

One: By supplying the argument for getWeather's second parameter: callback or by using default parameter value syntax to give that parameter a fallback value if it isn't supplied.

let weather = {

    apiKey:'dcaa6d5ea6bc87524fd5e38257edabba',
    city: 'montreal',   

    getWeather: function (city, callback = this.callback) {
        const xhr = new XMLHttpRequest();
        xhr.open(
            'get',
            'https://randomuser.me/api/'
    // There is a 401 error interpreted as unauthorized for the api below, thus why the above api is used to test
    //         ,`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${this.apiKey}`
            , true)

            xhr.onload = function () {
                if (xhr.status >= 200 && xhr.status < 300) {
                    const weatherData = JSON.parse(xhr.responseText);  
                    callback(weatherData)
                }

            }
        xhr.send()
    },

    callback: function (weatherData) {
        console.log(weatherData)
    },

    search: function () {
        this.getWeather('new york', this.callback);
        // the below also works
        //this.getWeather('new york');
    }

}

Two: By eager supply of some or all arguments of a function prior to invoking it via the engine provisioned closure method called bind on Function prototype.

In your case, a single parameter can be supplied to getWeather: which is city while a new parameter is given to the function assigned to xhr.onload, and that can be supplied a hard argument of this.callback by using Function.prototype.bind.

let weather = {

    apiKey:'dcaa6d5ea6bc87524fd5e38257edabba',
    city: 'montreal',   

    getWeather: function (city) {
        const xhr = new XMLHttpRequest();
        xhr.open(
            'get',
            'https://randomuser.me/api/'
    // There is a 401 error interpreted as unauthorized for the api below, thus why the above api is used to test
    //         ,`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${this.apiKey}`
            , true)

            xhr.onload = function (xhrCallback) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    const weatherData = JSON.parse(xhr.responseText);  
                    xhrCallback(weatherData)
                }

            }.bind(null, this.callback)
        xhr.send()
    },

    callback: function (weatherData) {
        console.log(weatherData)
    },

    search: function () {
        this.getWeather('new york')
    }

}

Finally, note that I had to use a randomuser api because the api in your question is not authorizing and you can swap it in back as needed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 SNOSeeds