Build a Weather App - Build a Weather App

Tell us what’s happening:

I can’t figure out why my code is failing Tests 16-22 & 24. My app does everything the stories request. My showWeather function IS calling getWeather to get the weather data. I’m handling the undefined values as well as when getWeather returns undefined in my showWeather function. If you select Paris and then hit the Get Weather button, it throws an alert saying “Something went wrong, please try later”. Please help!

Your code so far

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Weather App</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <header class="weather-header">
  <div class="laser laser-left"></div>
  <div class="laser laser-right"></div>
  <h1 id="city-name"></h1>
  <div id="location"></div>
  </header>
    <div id="weather-container">
      <div id="main-temperature"></div>
      <div id="weather-text"><div id="weather-main"></div><img id="weather-icon" src="" onerror="this.classList.add('broken')"></div>
      <div id="humidity"></div>
      <div id="feels-like"></div>
      <div id="wind"></div>
      <div id="wind-gust"></div>
      <div id="wind-direction"></div>
    </div>
    <div id="control-panel">
      <div id="control1">
        <h2>Weather For: </h2>
      </div>
      <div id="control2">
      <select id="city-select" name="cities">
        <option value=""></option>
        <option value="paris">Paris</option>
        <option value="london">London</option>
        <option value="tokyo">Tokyo</option>
        <option value="los angeles">Los Angeles</option>
        <option value="chicago">Chicago</option>
        <option value="new york">New York</option> 
      </select>
      </div>
      <div id="control3">
      <button id="get-weather-btn">Get Wheather</button>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>

const cityName = document.getElementById("city-name");
const citySelect = document.getElementById("city-select");

const leftLaser = document.querySelector(".laser-left");
const rightLaser = document.querySelector(".laser-right");

const mainTemp = document.getElementById("main-temperature");
const weatherMain = document.getElementById("weather-main");
const weatherIcon = document.getElementById("weather-icon");
const humidity = document.getElementById("humidity");
const feelsLike = document.getElementById("feels-like");
const wind = document.getElementById("wind");
const windGust = document.getElementById("wind-gust");
const windDir = document.getElementById("wind-direction");
const weatherAPI = "https://weather-proxy.freecodecamp.rocks/api/city/";
const getWeatherBtn = document.getElementById("get-weather-btn");


function changeCity(newCity) {

  leftLaser.classList.remove("fire");
  rightLaser.classList.remove("fire");
  cityName.classList.remove("hide-city", "reveal-city");

  void cityName.offsetWidth;

  cityName.classList.add("hide-city");

  leftLaser.classList.add("fire");
  rightLaser.classList.add("fire");

  setTimeout(() => {
    cityName.textContent = newCity;

    cityName.classList.remove("hide-city");
    cityName.classList.add("reveal-city");
  }, 800);

  setTimeout(() => {
    leftLaser.classList.remove("fire");
    rightLaser.classList.remove("fire");
    cityName.classList.remove("reveal-city");
  }, 900);
};

const getWeather = async (city) => {


  try {

    const weath = await fetch(`${weatherAPI}${city}`);
    const weathData = await weath.json();
    return weathData;

  } catch (error) {
    alert("Something went wrong, please try again later");
    console.log(error);
  }

};

const showWeather = async (city) => {

  if (!city) return;

  try {
    const currWeather = await getWeather(city);

    if (!currWeather) return;

  const weathArr = currWeather.weather;

  let temp = currWeather.main.temp;
  mainTemp.textContent = temp === undefined ? "N/A" : `${temp}° C`;

  weatherMain.textContent = weathArr[0].main === undefined ? "N/A" : weathArr[0].main;
  weatherIcon.src = weathArr[0].icon === undefined ? "" : weathArr[0].icon;

  humidity.textContent = currWeather.main.humidity === undefined ? "Humidity: N/A" : `Humidity: ${currWeather.main.humidity}%`;
  feelsLike.textContent = currWeather.main.feels_like === undefined ? "Feels Like: N/A" : `Feels Like: ${currWeather.main.feels_like}° C`;

  wind.textContent = currWeather.wind.speed === undefined ? "Wind: N/A" : `Wind: ${currWeather.wind.speed}m/s`;
  windGust.textContent = currWeather.wind.gust === undefined ? "Gusts: N/A" : `Gusts: ${currWeather.wind.gust}m/s`;
  } catch (error) {
    alert("Something went wrong, please try again later")
  }
  

}

getWeatherBtn.addEventListener("click", () => {
  let city = citySelect.value;
  setTimeout(() => {
    showWeather(city);
  }, 825);
  changeCity(city);
})
body {
  background-color: black;
  color: ivory;
}
#weather-container {
  width: 90%;
  height: 300px;
  background-color: #1D212E;
  border: 8px solid chartreuse;
  border-radius: 8px;
  margin-right: auto;
  margin-left: auto;
  margin-top: 10px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  place-items: center;
  color: chartreuse;
  font-size: 25px;
}

#control-panel {
  width: 90%;
  height: 100px;
  background-color: #1D212E;
  border: 8px solid chartreuse;
  border-radius: 8px;
  margin-right: auto;
  margin-left: auto;
  margin-top: 20px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-items: center;
  gap: 100px;
  padding: 8px;
  color: ivory;
}

h2 {
  font-family: impact;
  font-size: 24px;
}

#cities {
  width: 150px;
  height: 30px;
  background-color: #344148;
  color: chartreuse;
  border-radius: 5px;
}

#get-weather-btn {
  height: 35px;
  width: 115px;
  font-family: impact;
  font-size: 15px;
  color: #344148;
  border-radius: 5px;
  letter-spacing: 1px;
  background-color: ivory;
}

.weather-header {
  position: relative;
  width: 100%;
  height: 110px;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
}

#city-name {
  position: relative;
  z-index: 10;
  margin: 0;
  color: ivory;
  font-size: 3rem;
  text-align: center;
}

.laser {
  position: absolute;
  top: 50%;
  width: 50vw;
  height: 2px;
  background: chartreuse;
  box-shadow:
    0 0 10px chartreuse,
    0 0 25px chartreuse,
    0 0 50px chartreuse;
  opacity: 0;
  z-index: 5;
}

.laser-left {
  left: -50vw;
}

.laser-right {
  right: -50vw;
}

.laser-left.fire {
  animation: shootLeft 0.25s ease-out forwards;
}

.laser-right.fire {
  animation: shootRight 0.25s ease-out forwards;
}

@keyframes shootLeft {
  from {
    left: -50vw;
    opacity: 1;
  }

  to {
    left: 0;
    opacity: 1;
  }
}

@keyframes shootRight {
  from {
    right: -50vw;
    opacity: 1;
  }

  to {
    right: 0;
    opacity: 1;
  }
}

#city-name.hide-city {
  opacity: 0;
  transform: scale(0.8);
  filter: blur(8px);
}

#city-name.reveal-city {
  animation: revealCity 0.10s ease-in forwards;
}

@keyframes revealCity {
  0% {
    opacity: 0;
    color: chartreuse;
    transform: scale(0.5);
    filter: blur(12px);
    letter-spacing: 20px;
    text-shadow:
      0 0 20px chartreuse,
      0 0 50px chartreuse;
  }

  100% {
    opacity: 1;
    color: ivory;
    transform: scale(1);
    filter: blur(0);
    letter-spacing: 2px;
    text-shadow:
      0 0 8px rgba(255, 255, 240, 0.7),
      0 0 18px rgba(255, 255, 240, 0.35);
  }
}

#city-select {
  width: 125px;
  height: 35px;
  background-color: #344148;
  color: ivory;
  font-family: impact;
  font-size: 18px;
}

#weather-icon {
  width: 50px;
  height: 50px;
  display: inline-block;
}

#weather-main {
  display: inline-block;
}

img.broken {
  display: none;
}

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36

Challenge Information:

Build a Weather App - Build a Weather App

GitHub Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-weather-app/66f12a88741aeb16b9246c59.md at main · freeCodeCamp/freeCodeCamp · GitHub

use let getWeather instead of const getWeather because this value is being reassigned in the test.

Remove setTimeout as it is creating delay in fetching data and test is expecting data as fast as possible.

  • You should have an element with the id location for displaying the current location.

It seems like you forgot to add location.

Try logging weath when paris is selected. You’ll notice try/catch block never uses the alert in catch block.

Ok, I got you. Since the catch block is for catching network problems and technically a returned 404 is a successful network request, my catch block isn’t firing. Thank you! I fixed the other issues you mentioned, but the tests still fail as if I’m not displaying the returned API info in their designated id elements. I’m going to continue trouble shooting that issue. Hopefully I can figure it out, because everything is rendering to its correct element with the correct undefined fallback.

In case you are not able to figure it out, paste your JavaScript code here and we’ll try to help.

I’ve created a GitHub issue for this.

K, I think I’m going to need help. Because I’m looking at the test code on GitHub for tests 18-22 and I cannot for the life of me figure out why I’m failing them. I made sure that each API value is being rendered directly into a container with the desire ID value. I even thought maybe it was failing because my undefined fallback values for some of the values wasn’t strictly “N/A” but was stuff like “Wind: N/A” or “Gusts: N/A”, so I changed all undefined fallback values to be strictly “N/A”, but that still will not allow me to pass test 18-22. So I’m at a loss.

Please share your code so that we can look into it.

const cityName = document.getElementById("location");
const citySelect = document.getElementById("city-select");

const leftLaser = document.querySelector(".laser-left");
const rightLaser = document.querySelector(".laser-right");

const mainTemp = document.getElementById("main-temperature");
const weatherMain = document.getElementById("weather-main");
const weatherIcon = document.getElementById("weather-icon");
const humidity = document.getElementById("humidity");
const feelsLike = document.getElementById("feels-like");
const wind = document.getElementById("wind");
const windGust = document.getElementById("wind-gust");
const windDir = document.getElementById("wind-direction");
const weatherAPI = "https://weather-proxy.freecodecamp.rocks/api/city/";
const getWeatherBtn = document.getElementById("get-weather-btn");


function changeCity(newCity) {

  leftLaser.classList.remove("fire");
  rightLaser.classList.remove("fire");
  cityName.classList.remove("hide-city", "reveal-city");

  void cityName.offsetWidth;

  cityName.classList.add("hide-city");

  leftLaser.classList.add("fire");
  rightLaser.classList.add("fire");

  setTimeout(() => {
    cityName.textContent = newCity;

    cityName.classList.remove("hide-city");
    cityName.classList.add("reveal-city");
  }, 800);

  setTimeout(() => {
    leftLaser.classList.remove("fire");
    rightLaser.classList.remove("fire");
    cityName.classList.remove("reveal-city");
  }, 900);
};

let getWeather = async (city) => {


  try {

    const weath = await fetch(`${weatherAPI}${city}`);
    if (!weath.ok) {
      alert("Something went wrong, please try again later");
    }
    const weathData = await weath.json();
    return weathData;

  } catch (error) {
    console.log(error);
  }

};

const showWeather = async (city) => {

  if (!city) return;

  try {
    const currWeather = await getWeather(city);

    if (!currWeather) return;

  const weathArr = currWeather.weather;

  let temp = currWeather.main.temp;
  mainTemp.textContent = temp === undefined ? "N/A" : `${temp}° C`;

  weatherMain.textContent = weathArr[0].main === undefined ? "N/A" : weathArr[0].main;
  weatherIcon.src = weathArr[0].icon === undefined ? "" : weathArr[0].icon;

  humidity.textContent = currWeather.main.humidity === undefined ? "N/A" : `Humidity: ${currWeather.main.humidity}%`;
  feelsLike.textContent = currWeather.main.feels_like === undefined ? "N/A" : `Feels Like: ${currWeather.main.feels_like}° C`;

  wind.textContent = currWeather.wind.speed === undefined ? "N/A" : `Wind: ${currWeather.wind.speed}m/s`;
  windGust.textContent = currWeather.wind.gust === undefined ? "N/A" : `Gusts: ${currWeather.wind.gust}m/s`;

  const degrees = currWeather.wind.deg;
  
  const arrow = document.getElementById('wind-arrow');
  

  arrow.style.transform = `rotate(${degrees}deg)`;

  } catch (e) {
    console.log(e);
  }

}

function updateWindIndicator(apiData) {
  const degrees = apiData.wind.deg;
  
  const arrow = document.getElementById('wind-arrow');
  

  arrow.style.transform = `rotate(${degrees}deg)`;
  
}

getWeatherBtn.addEventListener("click", () => {
  const city = citySelect.value;
  showWeather(city);
  changeCity(city);
})
body {
  background-color: black;
  color: ivory;
}
#weather-container {
  width: 90%;
  height: 300px;
  background-color: #1D212E;
  border: 8px solid chartreuse;
  border-radius: 8px;
  margin-right: auto;
  margin-left: auto;
  margin-top: 10px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  place-items: center;
  color: chartreuse;
  font-size: 25px;
}

#control-panel {
  width: 90%;
  height: 100px;
  background-color: #1D212E;
  border: 8px solid chartreuse;
  border-radius: 8px;
  margin-right: auto;
  margin-left: auto;
  margin-top: 20px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  place-items: center;
  gap: 100px;
  padding: 8px;
  color: ivory;
}

h2 {
  font-family: impact;
  font-size: 24px;
}

#cities {
  width: 150px;
  height: 30px;
  background-color: #344148;
  color: chartreuse;
  border-radius: 5px;
}

#get-weather-btn {
  height: 35px;
  width: 115px;
  font-family: impact;
  font-size: 15px;
  color: #344148;
  border-radius: 5px;
  letter-spacing: 1px;
  background-color: ivory;
}

.weather-header {
  position: relative;
  width: 100%;
  height: 110px;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
}

#location {
  position: relative;
  z-index: 10;
  margin: 0;
  color: ivory;
  font-size: 3rem;
  text-align: center;
}

.laser {
  position: absolute;
  top: 50%;
  width: 50vw;
  height: 2px;
  background: chartreuse;
  box-shadow:
    0 0 10px chartreuse,
    0 0 25px chartreuse,
    0 0 50px chartreuse;
  opacity: 0;
  z-index: 5;
}

.laser-left {
  left: -50vw;
}

.laser-right {
  right: -50vw;
}

.laser-left.fire {
  animation: shootLeft 0.25s ease-out forwards;
}

.laser-right.fire {
  animation: shootRight 0.25s ease-out forwards;
}

@keyframes shootLeft {
  from {
    left: -50vw;
    opacity: 1;
  }

  to {
    left: 0;
    opacity: 1;
  }
}

@keyframes shootRight {
  from {
    right: -50vw;
    opacity: 1;
  }

  to {
    right: 0;
    opacity: 1;
  }
}

#location.hide-city {
  opacity: 0;
  transform: scale(0.8);
  filter: blur(8px);
}

#location.reveal-city {
  animation: revealCity 0.10s ease-in forwards;
}

@keyframes revealCity {
  0% {
    opacity: 0;
    color: chartreuse;
    transform: scale(0.5);
    filter: blur(12px);
    letter-spacing: 20px;
    text-shadow:
      0 0 20px chartreuse,
      0 0 50px chartreuse;
  }

  100% {
    opacity: 1;
    color: ivory;
    transform: scale(1);
    filter: blur(0);
    letter-spacing: 2px;
    text-shadow:
      0 0 8px rgba(255, 255, 240, 0.7),
      0 0 18px rgba(255, 255, 240, 0.35);
  }
}

#city-select {
  width: 125px;
  height: 35px;
  background-color: #344148;
  color: ivory;
  font-family: impact;
  font-size: 18px;
}

#weather-icon {
  width: 50px;
  height: 50px;
  display: inline-block;
}

#weather-main {
  display: inline-block;
}

img.broken {
  display: none;
}

.wind-container {
  text-align: center;
  font-family: sans-serif;
}

.compass-dial {
  width: 50px;
  height: 50px;
  border: 4px solid chartreuse;
  border-radius: 50%;
  position: relative;
  margin: 20px auto;
  background: #f9f9f9;
}

.arrow {
  width: 20px;
  height: 20px;
  font-size: 30px;
  font-weight: bold;
  position: absolute;
  top: calc(50% - 12px); 
  left: calc(50% - 10px);
  transition: transform 0.8s ease-in-out; 
  transform-origin: center center;
  color: #344148; 
}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Weather App</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
  <header class="weather-header">
  <div class="laser laser-left"></div>
  <div class="laser laser-right"></div>
  <h1 id="location"></h1>
  </header>
    <div id="weather-container">
      <div id="main-temperature"></div>
      <div id="weather-text"><div id="weather-main"></div><img id="weather-icon" src="" onerror="this.classList.add('broken')"></div>
      <div id="humidity"></div>
      <div id="feels-like"></div>
      <div id="wind"></div>
      <div id="wind-gust"></div>
      <div id="dir-text">Wind Direction:</div>
      <div class="wind-container">
      <div class="compass-dial">
        <div id="wind-arrow" class="arrow">↑</div>
      </div>
      </div>
      </div>
    <div id="control-panel">
      <div id="control1">
        <h2>Weather For: </h2>
      </div>
      <div id="control2">
      <select id="city-select" name="cities">
        <option value=""></option>
        <option value="paris">Paris</option>
        <option value="london">London</option>
        <option value="tokyo">Tokyo</option>
        <option value="los angeles">Los Angeles</option>
        <option value="chicago">Chicago</option>
        <option value="new york">New York</option> 
      </select>
      </div>
      <div id="control3">
      <button id="get-weather-btn">Get Wheather</button>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>

I don’t see location being updated over here.

Read the following instructions:

  • You should have an element with the id location for displaying the current location.

Ahh, ok that did it. I took the logic from my changeCity function and inserted it into my showWeather function, and then removed the setTimeout that wrapped the call to update location. That allowed me to pass the remaining tests, but it ruined the city name change animation lol. Thank you!

You could’ve just added below line to showWeather and it would’ve worked. That’s what I did, but at the end, you solved it! congratulations!

cityName.textContent = currWeather.name === undefined ? "N/A" : currWeather.name;

Happy coding!