FCC Weather App Example: Scope questions

Hi FCC, this is my first post! :slight_smile:

While looking through the code for FCC weather app (I know, I’m not supposed to look), I hit something in the Javascript that I can’t seem to figure out. I think it’s a question regarding scope??

In the top of the script, global variable currentTempInCelsius is defined.

var currentTempInCelsius;

Later, this variable is assigned the temperature value from the API response within the function getWeather (with some math rounding applied). And is then immediately sent to #temp to be displayed in the html.

function getWeather(lat, lon) {
  var urlString = api + lat + "&" + lon;
  $.ajax({
    url: urlString, success: function (result) {
  $("#city").text(result.name + ", ");
  $("#country").text(result.sys.country);
  currentTempInCelsius = Math.round(result.main.temp * 10) / 10;
  $("#temp").text(currentTempInCelsius + " " + String.fromCharCode(176));
  $("#tempunit").text(tempUnit);
  $("#desc").text(result.weather[0].main);
  IconGen(result.weather[0].main);
    }
  });
}

So far this makes complete sense to me. The API is called, the response comes, the temperature gets assigned to the variable. The value of the variable gets put in the #temp text and it displays on the site. Success!

What I don’t understand:

In another area, there is a separate function used to convert Celsius to Fahrenheit. In the last line it also uses currentTempInCelsius to successfully adjust the #temp text.

$("#tempunit").click(function () {
    var currentTempUnit = $("#tempunit").text();
    var newTempUnit = currentTempUnit == "C" ? "F" : "C";
    $("#tempunit").text(newTempUnit);
  
    if (newTempUnit == "F") {
      var fahTemp = Math.round(parseInt($("#temp").text()) * 9 / 5 + 32);
      $("#temp").text(fahTemp + " " + String.fromCharCode(176));
    } else {
      $("#temp").text(currentTempInCelsius + " " + String.fromCharCode(176));
}

but I’m not sure how it has access to the correct value of currentTempInCelsius.

I tested a few console.logs throughout various areas of the script to see what it would give me for currentTempInCelsius:

40 PM

Anywhere in the global space, it is still undefined. But within several different, unrelated, functions, the value is there!

My question: What has access to currentTempInCelsius? And where/how is that determined in this script?

I’m not sure if this is an API thing or what. I would have thought anything assigned to currentTempInCelsius would be accessible anywhere since it is a global variable.

(I hope all this makes sense! TIA)

Hey. I’m not sure where you put your console.log statements but that variable will be undefined until after the asynchronous call to the API completes.
At that point, it should be defined no matter where in the code it’s accessed from.

Is it possible that you put your log lines in places that would execute before the API call returned?

What @Nektario said is correct.

By defining it at the top of his script, the variable is accessible everywhere but the only place where it’s actually assigned is inside the success function of the Ajax call. Without that, it would still be undefined.

You can check this by deleting line 37.

(Also, I don’t see any problem at looking at the code, as long as you can learn from it).

Thanks everyone! It’s nice to know that it does work the way I would have believed it to work, by becoming globally accessible. That’s definitely more useful.

Still trying to understand some things. I just played around with it some more to try some precise spots for “console.log(currentTempInCelsius);”
–I put it at the very end of the code, it still read undefined (long after the API was successfully called).
–I tried putting it on line12, right after the getWeather function (which contains the $.ajax function, so should be after successful API call)

Both returned undefined. Is this something to do with hoisting? Is console.log triggered before the functions?

1 Like

The Ajax call is asynchronous, meaning that the javascript execution moves to the next line as soon as the request is sent; it doesn’t wait for a response.

Try doing this, change line 37 from:

currentTempInCelsius = Math.round(result.main.temp * 10) / 10;

to:

setTimeout(function() {
 currentTempInCelsius = Math.round(result.main.temp * 10) / 10;
}, 500);

You will see that the temperature will be undefined at the beginning but after switching to fahrenheit and back to celsius (in other words, after the else statement at line 25 that calls currentTempInCelsius again) it will have the correct value. That’s because the value is still being set but, by that time, javascript is already at the next line, the one assigning the value to #temp:

$("#temp").text(currentTempInCelsius + " " + String.fromCharCode(176));

1 Like

Asynchronous! Well that makes obvious sense now!

Thank you so much noyb and rmdawson71 for patiently talking me through that until it clicked :blush:

1 Like