Search code examples
javascriptjsonasynchronousgoogle-maps-api-3weather-api

Javascript return value from asynchronous function


I know it's a very popular and many times answered topics, but I

couldn't fully understand it's application in my case.

I am learning my way through Javascript, and I am stuck trying to return a value from async function. Essentially, I want my function to take a city name and return its current temperature from APIXU Weather API (https://www.apixu.com).

Then, I wanted to use this function inside my other Google API function. This function takes id of the clicked marker, finds it's city name in the array of places, and displays information in an infowindow, such as title of the place, weather of a city and Google Streetview. My initial plan was to use getWeather function inside populateInfoWindow to find the weather of a city. Is it possible to achieve it? Because from what I understand using asynchronous function inside synchronous, will make the latest one asynchronous. Another possible route I was going to choose is to get the weather of all places in the array on document load and just take the information from the array in populateInfoWindow function. But I am afraid that this will be repetitive and unnecessary.

To your opinion, what would be the best way to accomplish it and how to avoid similar problems?

Here is the code:

//Get current forecast from weather API
        function getWeather(city) {
            var weatherAPIXU = "http://api.apixu.com/v1/current.json?key=XXXXXXXXXXXXXXX&q=" + city;
            $.getJSON(weatherAPIXU, function(data) {
                var forecast = data.current.temp_c;
                var curWeather = forecast + '° C';
                 return curWeather
            });
        }

// Return a city name that matches a marker id
function getCityName(locations, marker) {
    for (var i = 0, iLen = locations.length; i < iLen; i++) {
        if (locations[i].id == marker.id) return locations[i].city;
    }
}

// This function populates the infowindow when the marker is clicked. It'll only allow
// one infowindow which will open at the marker that is clicked, and populate based
// on that markers position.
function populateInfoWindow(marker, infowindow) {
    // Check to make sure the infowindow is not already opened on this marker.
    if (infowindow.marker != marker) {
        // Clear the infowindow content to give the streetview time to load.
        infowindow.setContent('');
        infowindow.marker = marker;
        // Make sure the marker property is cleared if the infowindow is closed.
        infowindow.addListener('closeclick', function() {
            infowindow.marker = null;
        });
        var streetViewService = new google.maps.StreetViewService();
        var radius = 50;
        var city = getCityName(locations, marker);
        console.log(city);
        var weatherInCity = getWeather(city);
        console.log(weatherInCity);
        // In case the status is OK, which means the pano was found, compute the
        // position of the streetview image, then calculate the heading, then get a
        // panorama from that and set the options
        var getStreetView = function(data, status) {
            if (status == google.maps.StreetViewStatus.OK) {
                var nearStreetViewLocation = data.location.latLng;
                var heading = google.maps.geometry.spherical.computeHeading(
                    nearStreetViewLocation, marker.position);
                infowindow.setContent('<div>' + marker.title + '' + weatherInCity +
                    '</div><div id="pano"></div>');
                var panoramaOptions = {
                    position: nearStreetViewLocation,
                    pov: {
                        heading: heading,
                        pitch: 30
                    }
                };
                var panorama = new google.maps.StreetViewPanorama(
                    document.getElementById('pano'),
                    panoramaOptions);
            } else {
                infowindow.setContent('<div>' + marker.title +
                    '</div>' +
                    '<div>No Street View Found</div>');
            }
        };
        // Use streetview service to get the closest streetview image within
        // 50 meters of the markers position
        streetViewService.getPanoramaByLocation(marker.position,
            radius, getStreetView);
        // Open the infowindow on the correct marker.
        infowindow.open(map, marker);
    }
}

Solution

  • You cannot return object like this as it is callback function. You can write you logic inside the callback function.

    function getWeather() {
    var city = $("#txtCity").val();
        var weatherAPIXU = "http://api.apixu.com/v1/current.json?key=XXXXXXX&q=" + city;
        $.getJSON(weatherAPIXU, function(data) {
            var forecast = data.current.temp_c;
            var curWeather = forecast + '° C';
            $("#lblTemp").html(curWeather)
    
        });
    

    The Other option which is not recommended is declare a global variable and assign the return value to the global variable.

    var CurrentWeather = null
    function getWeather(city) {
    
    var weatherAPIXU = "http://api.apixu.com/v1/current.json?key=XXXXX&q=" + city;
    $.getJSON(weatherAPIXU, function(data) {
        var forecast = data.current.temp_c;
        var curWeather = forecast + '° C';
        $("#lblTemp").html(curWeather)
         CurrentWeather = curWeather;
    });