Build a Weather App

So, everything looks to be alright when I press the button, but i don’t understand why steps 18-22 are still not being fulfilled.

I checked the web console, but it said something about a non-valid URL.

I surmised it might have something to do with the space between the city words?

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Weather App</title>
    <link rel="stylesheet" href="./styles.css">
  </head>

  <body>
    <div id="weather-container">
      <div id="weather-display">
        <div id="current-weather">
          <img id="weather-icon" src=""/>
          <p id="weather-main"></p>
        </div>
        
        <p class="main-temperature">Main Temp: <span id="main-temperature"></span></p>
        <p class="feels-like">Feels like: <span id="feels-like"></span></p>
        <p class="humidity">Humidity: <span id="humidity"></span></p>
        <p class="wind">Wind: <span id="wind"></span></p>
        <p class="wind-gust">Gusts: <span id="wind-gust"></span></p>
        
        <p class="location">Location: <span id="location"></span></p>
      </div>
      <div id="weather-selector">
        <p>Get Weather:</p>
        <select id="cities">
          <option value=""></option>
          <option value="new york">New York</option>
          <option value="los angeles">Los Angeles</option>
          <option value="chicago">Chicago</option>
          <option value="paris">Paris</option>
          <option value="tokyo">Tokyo</option>
          <option value="london">London</option>
        </select>
        <button id="get-weather-btn">Get Weather</button>
      </div>
    </div>
    <script src="./script.js"></script>
  </body>
</html>
body{
  font-family: "Roboto Mono", system-ui;
}

#weather-container{
  display: flex;
  flex-direction: column-reverse;
}

#weather-selector{
  border: 5px solid black;
  padding: 15px;
}

#weather-display{
  border: 5px solid black;
  padding: 10px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}

#current-weather{
  grid-column: 1 / -1;
  margin: auto;
  display: flex;
  gap: 10px;
  justify-content: center;
  align-items: center;

}

#weather-icon{
  width: 5rem;
}

#weather-main{
  font-size: 2rem;
  font-weight: 800;
}

#weather-display > p > span{
  font-size: 1.5rem;
}
const getWeatherBtn = document.getElementById("get-weather-btn");

const weatherIcon = document.getElementById("weather-icon");
const mainTemp = document.getElementById("main-temperature");
const feelsLike = document.getElementById("feels-like");
const humiditySpan = document.getElementById('humidity');
const windSpan = document.getElementById('wind');
const gustSpan = document.getElementById('wind-gust');
const mainWeather = document.getElementById("weather-main");
const locationSpan = document.getElementById("location");


const citySelector = document.getElementById("cities");

async function getWeather(city){
  try{
  
    let res = await fetch(`https://weather-proxy.freecodecamp.rocks/api/city/${city}`);
    if (!res.ok){
      throw new Error("Error occurred! Weather data does not exist!");
    }
    let data = await res.json();
    return data;
  } catch(err){
    
    console.error(err);

    return null;
  }
  
}
async function showWeather(city){
  
  const data = await getWeather(city);
  if (!data || !data.weather){
    alert("Something went wrong, please try again later");
    return;
  }
  //console.log(data);
  const { name, weather, main, wind} = data;

  const [{icon, main: main_weather}] = weather;
  const {temp, feels_like, humidity} = main;
  const {speed, gust} = wind;
 
  if (icon === undefined){
    weatherIcon.alt = "N/A";
  } else {
    weatherIcon.src = icon;
  }
  
  mainTemp.innerHTML = (temp !== undefined) ? `${temp}&deg;C` : "N/A";
  feelsLike.innerHTML = (feels_like !== undefined) ? `${feels_like}&deg;C` : "N/A";
  humiditySpan.innerHTML = (humidity !== undefined) ? `${humidity}%` : "N/A";
  windSpan.innerHTML = (speed !== undefined) ? `${speed} m/s` : "N/A";
  gustSpan.innerHTML = (gust !== undefined) ? `${gust} m/s` : "N/A";
  mainWeather.innerHTML = (main_weather !== undefined) ? `${main_weather}` : "N/A";
  locationSpan.innerHTML = (name !== undefined) ? `${name}` : "N/A";
  
}
  

let city = "";
citySelector.addEventListener("change", (e) => {
  city = e.target.value;

})

getWeatherBtn.addEventListener("click", () => {
  if (city !== ""){
    
    showWeather(city); 
    
  }
})

greetings, always include exercise / step url so that we can also see its full context. happy coding :slight_smile:

These’ are the steps I’m currently trying to fulfill.

18. When New York is selected the showWeather function should display the data from the API in the respective HTML elements. If the value from the API is undefined, you should show N/A.
19. When Chicago is selected the showWeather function should display the data from the API in the respective HTML elements. If the value from the API is undefined, you should show N/A.
21. When Tokyo is selected the showWeather function should display the data from the API in the respective HTML elements. If the value from the API is undefined, you should show N/A.
22. When Los Angeles is selected the showWeather function should display the data from the API in the respective HTML elements. If the value from the API is undefined, you should show N/A.

and

24. When Paris is selected the app should show an alert with Something went wrong, please try again later.

I just noticed something.

The only test of the showWeather function for each city where the test is complete is London…the last one in the select menu.

Any reason why this is

maybe there isn’t a change event being dispatched by the tests

Okay, so I did try to change the order of the option tags, but London is still the only city where the test work.

I even tried to capitalize the value of the london tag, but test 20 (London) still works.

I did notice this in my website console.

Error: AssertionError: expected 'https://cdn.freecodecamp.org/weather-…' to equal 'https://cdn.freecodecamp.org/weather-…'
    <anonymous> https://www.freecodecamp.org/js/test-runner/5.4.1/dom-test-evaluator.js line 2 > eval:31
dom-test-evaluator.js:2:255516

Error: AssertionError: expected 'https://cdn.freecodecamp.org/weather-…' to equal 'https://cdn.freecodecamp.org/weather-…'
    <anonymous> https://www.freecodecamp.org/js/test-runner/5.4.1/dom-test-evaluator.js line 2 > eval:31
dom-test-evaluator.js:2:255516

Error: AssertionError: expected 'https://cdn.freecodecamp.org/weather-…' to equal 'https://cdn.freecodecamp.org/weather-…'
    <anonymous> https://www.freecodecamp.org/js/test-runner/5.4.1/dom-test-evaluator.js line 2 > eval:31
dom-test-evaluator.js:2:255516

Error: AssertionError: expected 'https://cdn.freecodecamp.org/weather-…' to equal 'https://cdn.freecodecamp.org/weather-…'
    <anonymous> https://www.freecodecamp.org/js/test-runner/5.4.1/dom-test-evaluator.js line 2 > eval:31
dom-test-evaluator.js:2:255516

Object { message: "the given combination of arguments (undefined and string) is invalid for this assertion. You can use an array, a map, an object, a set, a string, or a weakset instead of a string", showDiff: false, stack: "", … }
dom-test-evaluator.js:2:255516

Source map error: Error: URL constructor:  is not a valid URL.
Stack in the worker:resolveSourceMapURL@resource://devtools/client/shared/source-map-loader/utils/fetchSourceMap.js:56:22
getOriginalURLs@resource://devtools/client/shared/source-map-loader/source-map.js:73:24
workerHandler/</<@resource://devtools/client/shared/worker-utils.js:115:52
workerHandler/<@resource://devtools/client/shared/worker-utils.js:113:13


Resource URL: about:srcdoc
Source Map URL: 

I’m not sure what this means.

that’s not what I mean with my comment. You are using an event listener on change. What happens if that event listener never listen to a change event?

Oh…..facepalm

I changed it. I got rid of the event listener on the select and put the city in the button listener.

getWeatherBtn.addEventListener("click", () => {
  let city = citySelector.value;
  if (city !== ""){
    showWeather(city.split(" ").join('%20')); 
  }
})

It worked.

Thank you very much.

I don’t fully understand why this is so with the tests, but I’m glad I got it done.

honestly, it did not came to mind when writing them. When changing values programmatically, you need to create the event too, and I only wrote the click event, not the change event, and it did not came to mind to anyone reviewing the code either

you can open an issue to bring this up if you want GitHub · Where software is built

Were you intending a pure approach to the code?

In my code, city was a global variable, and so when I use the change event listener to the selector, the global variable is changed.

In the code I changed, city is local to the btn listener, which means technically no outward change other than the DOM.

(Although, is there a way to consider multiple approaches to the project regarding the tests?)

the way to propose the change is to open an issue