Weather app problems with Promise, $.when(), debugging

Whenever the page starts and my function getWeather calls itself, I feel like it is not considering my $.when(getWeatherData()) .done call. getWeatherData returns itself, but it does not consider the thisUrl var and my getWeather .fails instead. However, if I run the code in debug mode it passes my promise getWeather Data and works as intended.

Am I making and implementing this promise incorrectly? And if this promise function is not going to work with the variables above the return, is there a better way to call this promise and still be able to concatenate my geoposition call?

I also considered maybe returning an $.ajax ({beforeSend: … }) however I don’t see how I would be able to concatenate all the data that I need into the url.

On a side note, I feel like my problem is me not understanding Asynchronous and promises. But I am under the impression that making this promise function and calling it with the $.when object method guarantees that the entire promise function would run from start to finish.

    $(document).ready(function(){
        
        
       

        var $temp = $("#temp");
        var $tempSymb = $("#tempSymb");



        getWeatherData = function(){
            var pos = {};
            navigator.geolocation.getCurrentPosition(function(position) {
             pos.lat = position.coords.latitude;
             pos.lon = position.coords.longitude;
            });
            var key = "###";
            var thisUrl = 'https://api.wunderground.com/api/' + key + '/conditions/q/' + pos.lat + ',' + pos.lon + '.json'
            return $.getJSON(thisUrl);
        }
        

         var getWeather = function () {
             $.when(getWeatherData())
                .done(function(weather){
                    var thisWeather = weather;
                    console.log(thisWeather);
                    var tempF = thisWeather.current_observation.temp_f;
                    var tempC = thisWeather.current_observation.temp_c;
                    $("#location").text(thisWeather.current_observation.display_location.city);
                    $temp.text(tempF);
                    $("#img").attr("src", thisWeather.current_observation.icon_url);
                    $("#dateTime").text(thisWeather.current_observation.local_time_rfc822);
            })
            .fail(function(){
                alert("Unable to get weather");
            });
            
        }();
    });

<!-- language: lang-html -->


        <div class="container">
          <div class="row">
            <div id="forecast">
              <h1>Weather at <span id="location"> </span></h1>
              <div id="imgdiv">
              <img id="img" src=""/>
              </div>
              <p>It is currently <button class="btn btn-primary"><span id="temp"> </span><span id="tempSymb">°F</span></button> with <span id="desc"> </span></p>
              <p>Wind: <span id="wind"></span></p>
              <p>Current Time/Date: <span id="dateTime"></span></p>
              </div>
          </div>
        </div>
        
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

getCurrentPosition is an asynchronous function. You’re not populating pos like you think you are. All of your apps code needs to run in the callback to getCurrentPosition.

Oh wow I didn’t even realize this was an async function lol. for the sake of practice and organizing re-usable code, would you suggest that I have everything wrapped up in the getCurrentPosition callback or is there an easy way just to set this function up in its own promise.

Yeah, if you want to make getCurrentPosition to be a promise, it’s pretty straightforward. You can implement any function as a promise.

function getLocation() {
    return new Promise(function(resolve, reject) {
        navigator.geolocation.getCurrentPosition(function(position) {
            resolve({lat: position.coords.latitude, lon: position.coords.longitude});
        }, reject); // we can pass reject directly as the second parameter and it will receive any errors thrown
    }); 
}

resolve is the function that takes the happy path (ie, your then function), and reject handles errors. Now you can use it thusly

getLocation()
    .then(getWeather)
    .then(putDataOnPage)
    .catch(handleErrors)

It’s not a drop-in replacement for what you’ve got already. I’m using the A+ standard then and catch methods rather than done and fail. They’re functionally identical, but done and fail are specific to jQuery. Your use of when is unnecessary, but the method is very useful for using multiple promises together. Things are looking good, though! Promises are definitely the way to go.

1 Like

Awesome! thank your for the explanation! yeah I figured .when was not called for but I just wanted to make sure I understood what I was doing with it lol. ill look more into implementing more promises this way instead.

1 Like