Hướng dẫn thử thách
1 / 1
Build a Weather App
In this lab, you'll build an app that provides weather information from different cities.
You will use a weather API. The output data has the following format:
```json
{
"weather": [
{
"main": "Clear",
"description": "clear sky",
"icon": "https://cdn.freecodecamp.org/weather-icons/01n.png" // icon representing the weather
}
],
"main": {
"temp": 2.62, // temperature in C
"feels_like": 0.84, // temperature in C
"temp_min": 1.72, // min temperature of the day in C
"temp_max": 3.49, // max temperature of the day in C
"pressure": 1010, // atmospheric pressure in hPa
"humidity": 81 // humidity in %
},
"visibility": 10000, // distance in meters
"wind": {
"speed": 1.79, // speed of the wind in m/s
"deg": 285, // orientation of the wind in degrees
"gust": 3.13 // gust speed in m/s
},
"name": "London"
}
```
**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab.
**User Stories:**
1. You should have a `button` element with an `id` of `get-weather-btn`.
1. You should have a `select` element with seven `option` elements nested within it. The first option should have an empty string as its text and `value` attribute. The rest should have the following for their text and values (with the value being lowercase):
- New York
- Los Angeles
- Chicago
- Paris
- Tokyo
- London
1. If no city is selected, pressing the button should do nothing.
1. If a city is selected, elements to show the weather should appear:
- You should have an `img` element with the id `weather-icon` for displaying the weather icon.
- You should have an element with the id `main-temperature` for displaying the main temperature.
- You should have an element with the id `feels-like` for displaying what the temperature feels like.
- You should have an element with the id `humidity` for displaying the amount of humidity in air.
- You should have an element with the id `wind` for displaying the wind speed.
- You should have an element with the id `wind-gust` for displaying the wind gust.
- You should have an element with the id `weather-main` for displaying the main weather type.
- You should have an element with the id `location` for displaying the current location.
1. You should have an asynchronous function named `getWeather` that fetches the weather information from the `https://weather-proxy.freecodecamp.rocks/api/city/<CITY>` API and returns it. Note that this API returns data using the metric system, that means m/s for wind speed, and Celsius for the temperature.
1. The `getWeather` asynchronous function should accept a city as its argument.
1. You should handle any errors that occur within the `getWeather` function and log them to the console.
1. You should have an asynchronous `showWeather` function that accepts a city as parameter.
1. The `showWeather` function should call the `getWeather` function to retrieve the weather data for the selected city from the dropdown.
1. If the `getWeather` function had an error, the app should only show an alert that says `Something went wrong, please try again later`.
1. If the data from `getWeather` are usable, the `showWeather` function should display the weather data in the corresponding elements. If a certain value from the API is `undefined`, you should write `N/A` in the corresponding element.
**Note:** Neither the `getWeather` function nor the `showWeather` function should be declared using `const`, since the tests need to reassign them. Also, the tests will take time to complete, so as long as you see `// running tests` in the console, they are being executed.
# --before-all--
```js
window.fetch = (url) => {
const city = decodeURIComponent(url.split("/").pop());
const cityMap = {
"new york": {
coord: { lon: -74.0059, lat: 40.7127 },
weather: [
{
id: 804,
main: "Clouds",
description: "overcast clouds",
icon: "https://cdn.freecodecamp.org/weather-icons/04d.png",
},
],
base: "stations",
main: {
temp: 14.33,
feels_like: 13.2,
temp_min: 13.21,
temp_max: 15.54,
pressure: 1008,
humidity: 53,
sea_level: 1008,
grnd_level: 1007,
},
visibility: 10000,
wind: { speed: 3.6, deg: 40 },
clouds: { all: 100 },
dt: 1732123426,
sys: {
type: 1,
id: 4610,
country: "US",
sunrise: 1732103363,
sunset: 1732138471,
},
timezone: -18000,
id: 5128581,
name: "New York",
cod: 200,
},
"los angeles": {
coord: { lon: -118.2437, lat: 34.0522 },
weather: [
{
id: 800,
main: "Clear",
description: "clear sky",
icon: "https://cdn.freecodecamp.org/weather-icons/01d.png",
},
],
base: "stations",
main: {
temp: 17.24,
feels_like: 15.88,
temp_min: 14.84,
temp_max: 19.62,
pressure: 1023,
humidity: 33,
sea_level: 1023,
grnd_level: 1003,
},
visibility: 10000,
wind: { speed: 2.57, deg: 70 },
clouds: { all: 0 },
dt: 1732123664,
sys: {
type: 2,
id: 2075946,
country: "US",
sunrise: 1732113063,
sunset: 1732150008,
},
timezone: -28800,
id: 5368361,
name: "Los Angeles",
cod: 200,
},
chicago: {
coord: { lon: -87.6298, lat: 41.8781 },
weather: [
{
id: 802,
main: "Clouds",
description: "scattered clouds",
icon: "https://cdn.freecodecamp.org/weather-icons/03d.png",
},
],
base: "stations",
main: {
temp: 8.91,
feels_like: 4.91,
temp_min: 7.86,
temp_max: 9.44,
pressure: 1009,
humidity: 50,
sea_level: 1009,
grnd_level: 987,
},
visibility: 10000,
wind: { speed: 9.39, deg: 285, gust: 12.52 },
clouds: { all: 40 },
dt: 1732123645,
sys: {
type: 2,
id: 2010190,
country: "US",
sunrise: 1732106817,
sunset: 1732141557,
},
timezone: -21600,
id: 4887398,
name: "Chicago",
cod: 200,
},
london: {
coord: { lon: -0.1278, lat: 51.5074 },
weather: [
{
id: 800,
main: "Clear",
description: "clear sky",
icon: "https://cdn.freecodecamp.org/weather-icons/01n.png",
},
],
base: "stations",
main: {
temp: 2.62,
feels_like: 0.84,
temp_min: 1.72,
temp_max: 3.49,
pressure: 1010,
humidity: 81,
sea_level: 1010,
grnd_level: 1005,
},
visibility: 10000,
wind: { speed: 1.79, deg: 285, gust: 3.13 },
clouds: { all: 1 },
dt: 1732123462,
sys: {
type: 2,
id: 2075535,
country: "GB",
sunrise: 1732087658,
sunset: 1732118707,
},
timezone: 0,
id: 2643743,
name: "London",
cod: 200,
},
tokyo: {
coord: { lon: 139.6917, lat: 35.6895 },
weather: [
{
id: 501,
main: "Rain",
description: "moderate rain",
icon: "https://cdn.freecodecamp.org/weather-icons/10n.png",
},
],
base: "stations",
main: {
temp: 8.71,
feels_like: 5.38,
temp_min: 8.08,
temp_max: 9.81,
pressure: 1015,
humidity: 92,
sea_level: 1015,
grnd_level: 1014,
},
visibility: 7000,
wind: { speed: 6.69, deg: 330 },
rain: { "1h": 2.05 },
clouds: { all: 75 },
dt: 1732123711,
sys: {
type: 2,
id: 268395,
country: "JP",
sunrise: 1732137787,
sunset: 1732174284,
},
timezone: 32400,
id: 1850144,
name: "Tokyo",
cod: 200,
},
};
return Promise.resolve({
ok: city !== "paris",
json: () => Promise.resolve(cityMap[city]),
});
};
// function that construct an object with the id-value pairs that we expect in the page from an object
const helper = (wobj) => ({
"weather-icon": wobj.weather[0].icon,
"main-temperature": wobj.main.temp || "N/A",
"feels-like": wobj.main.feels_like || "N/A",
humidity: wobj.main.humidity || "N/A",
wind: wobj.wind.speed || "N/A",
"wind-gust": wobj.wind.gust || "N/A",
"weather-main": wobj.weather[0].main || "N/A",
location: wobj.name || "N/A",
});
const timeout = milliseconds =>
new Promise(resolve => {
return setTimeout(resolve, milliseconds)
});
```
Vượt qua bài kiểm tra hiện tại để mở khóa bài tiếp theo.
main.sh
UTF-8 • Tab Size: 2Kiểm tra bài:⌘↵