Check out my FreeCodeCamp Weather App

Hi fellow developers, today I want to share with you all the fun I had building the freecodecamp-weather-app. First of all, check it out here. If you like what you’ll see come back to this article.

This was a fun challenge for me because it allowed me to play a bit with APIs and play with some JSON data which I love to do as well as to make some CSS animations depending on the weather. The requirements where those:

  1. User Story: I can see the weather in my current location.
  2. User Story: I can see a different icon or background image (e.g. snowy mountain, hot desert) depending on the weather.
  3. User Story: I can push a button to toggle between Fahrenheit and Celsius.

In order to get the location in the browser you need to use something called the HTML5 Geolocation. This interface represents an object that is capable of programmatically obtain the position of a device, basically you will ask the user for permission to obtain the latitude and longitude of their location and use it to make the GET request to the FCC-Open-Weather API. All this comes from the Navigator Object (or interface) that has a bunch of read-only properties (or methods) like the navigator.geolocation, and the GeolocationObject has also 3 methods:

  1. Geolocation.getCurrentPosition()
  2. Geolocation.watchPosition()
  3. Geolocation.clearWatch()

We are interested is the number 1: Geolocation.getCurrentPosition();

function findMyLocation() {
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
console.log("Geolocation is not supported in your browser or you didn't allow it");
}

function showPosition(position) {
console.log("Your latitude is: " + position.coords.latitude + "\n" + "Your longitude is: " + position.coords.longitude);
}
}

console.log(findMyLocation());

We are creating above a function called getLocation that will check if the navigator.geolocation object is supported by the browser ( if it’s true), then it will use the function showPosition as a parameter to display the latitude and longitude. If you’re pretty curious you can check the Geolocation API Specification here:

or check the MDN Web Docs here:

OK, now that we have the latitude and longitude, let’s use it to make a n HTTP GET request to the FCC-Open-Weather API. Time for some AJAX ninja moves:

function findMyLocation() {

if (!navigator.geolocation) {
console.log("Geolocation is not supported by your browser");
return;
}

function success(position) {
let latitude = "lat=" + position.coords.latitude;
let longitude = "lon=" + position.coords.longitude;

let askLoc = `https://fcc-weather-api.glitch.me/api/current?${latitude}&${longitude}`

//Make the AJAX requestlet xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
let resp = JSON.parse(this.responseText);
console.log(resp);
}
}
xhttp.open("GET", `${askLoc}`, true);
xhttp.send();
};
//calling the navigator object
navigator.geolocation.getCurrentPosition(success);

}

findMyLocation();

As we see, we are making the GET request inside the success function, I am assigning the latitude and longitude to variables, then putting that into a string on the variable askLoc and making the GET request. I am parsing the returning JSON data from the fcc-weather- api and putting into the variable resp, then console.log that to see the JSON, this is the data you should see (with your location) :

{coord: {…}, weather: Array(1), base: "stations", main: {…}, visibility: 16093, …}
base
:
"stations"
clouds
:
{all: 75}
cod
:
200
coord
:
{lon: -80.31, lat: 25.72}
dt
:
1525172160
id
:
4156857
main
:
{temp: 23.26, pressure: 1020, humidity: 64, temp_min: 22, temp_max: 24}
name
:
"Glenvar Heights"
sys
:
{type: 1, id: 689, message: 0.0039, country: "US", sunrise: 1525171451, …}
visibility
:
16093
weather
:
Array(1)
0
:
{id: 803, main: "Clouds", description: "broken clouds", icon: "https://cdn.glitch.com/6e8889e5-7a72-48f0-a061-863548450de5%2F04d.png?1499366020964"}
length
:
1
__proto__
:
Array(0)
wind
:
{speed: 5.7, deg: 80}
__proto__
:
Object

Now you can use that data to show the weather, for the purpose of simple demonstration I will not include the different CSS animations that I used depending on the weather (but you can see those in my link at the top of this article). I will show you the 3 user stories that this challenge is requesting: to show the location, the weather description, an image or icon depending on the weather, and a button to toggle between Celsius and Fahrenheit. I will be using Bootstrap 4 which will help us to display a fantastic card with all this information. We will put the javascript file in a js folder and keep the html outside. No CSS folder this time ( yay Bootstrap!).

Here’s the HTML, it has a card where we will display all the information:

<!doctype html>
<html lang="en">

<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">

<title>FreeCodeCamp Weather App</title>
</head>
<style>
body {
background-color: #87ceeb;
}
</style>

<body>
<div class="container">
<div class="row">
<div class="card mx-auto" style="width: 18rem;">
<figure class="card-img-top"></figure>
<!-- <img class="card-img-top" src="" alt="Card image cap"> -->
<div class="card-body text-center">
<h5 class="card-title"></h5>
<p class="card-text"></p>
<p class="temp"></p>
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<label id="celsius" class="btn btn-secondary active">
<input type="radio" name="options" autocomplete="off" checked>℃
</label>
<label id="fahrenheit" class="btn btn-secondary">
<input type="radio" name="options" autocomplete="off">℉
</label>
</div>
</div>
</div>
</div>
</div>


<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
<!-- Loading our local js file -->
<script src="js/ex.js"></script>
</body>

</html>

Here’s our javascript file finished, notice a few things:

  1. I included the jQuery $(document).ready() to execute everything after the HTML has loaded.
  2. I included also the ‘use strict’ mode. In general this is a good practice.
  3. The temperature is returned in Celsius by default with fractional digits. I used Math.trunc() to remove those and leave only the decimal integers.

4. To convert from celsius to fahrenheit it’s just math my friend: ℉=(℃*1.8)+32. If you want to learn more check:

5. Check the event listener to switch the toggle button between Celsius and Fahrenheit.

Enough talking, here’s the JavaScript file finished:

$(document).ready(function () {
'use strict';
function findMyLocation() {

if (!navigator.geolocation) {
console.log("Geolocation is not supported by your browser");
return;
}

function success(position) {
let celsius = "℃";
let fahrenheit = "℉";
let latitude = "lat=" + position.coords.latitude;
let longitude = "lon=" + position.coords.longitude;

let askLoc = `https://fcc-weather-api.glitch.me/api/current?${latitude}&${longitude}`

//Make the AJAX requestlet xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
let resp = JSON.parse(this.responseText);
console.log(resp);
$(".card-title").text(`${resp.name}, ${resp.sys.country}`);
$(".card-text").text(`${resp.weather[0].description}`);
$(".card-img-top").html(`<img class="card-img-top" src="${resp.weather[0].icon}" alt="Weather icon">`);
$("label#celsius").text(`${Math.trunc(resp.main.temp)} ${celsius}`);

//adding two events listener
$("#fahrenheit").on("click", function () {
$("#celsius").html(`${celsius}`);
$("#fahrenheit").text(`${Math.trunc(resp.main.temp * 9 / 5 + 32)} ${fahrenheit}`)
})
$("#celsius").on("click", function () {
$("label#fahrenheit").html(`${fahrenheit}`);
$("label#celsius").text(`${Math.trunc(resp.main.temp)} ${celsius}`);
})

}
}
xhttp.open("GET", `${askLoc}`, true);
xhttp.send();
};
//calling the navigator object
navigator.geolocation.getCurrentPosition(success);

}
findMyLocation();
});

I hope you enjoyed this short and simple tutorial. If you would like to clone the project and run it locally get it here in my GitHub.

Technology is my passion, programming is the tool I use to express that feeling. I am constantly learning, listening and helping others to be better.