Project: Weather Dashboard
💻 JavaScriptBuild a small dashboard that fetches weather data and renders it with loading and error states.
This project combines DOM updates, events, async requests and error handling into one practical page.
- Fetch data from an API.
- Render dynamic content safely.
- Handle loading, success and error states.
Project Plan
Build a search field, a button and a results area. When the user submits a city, fetch the weather and display the temperature, condition and wind.
Fetch and Render
Use textContent rather than innerHTML for values that come from an API. It prevents markup from being injected into your page.
const form = document.querySelector("#search-form");
const result = document.querySelector("#result");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const city = form.elements.city.value.trim();
if (!city) return;
result.textContent = "Loading…";
try {
const response = await fetch(`/api/weather?city=${encodeURIComponent(city)}`);
if (!response.ok) throw new Error("City not found");
const data = await response.json();
result.textContent = `${data.city}: ${data.temperature}°C, ${data.condition}`;
} catch (error) {
result.textContent = error.message;
}
});Polish
- Disable the button while loading.
- Show the last updated time.
- Keep the layout stable so text does not jump.
- Test with a missing city and a network failure.
Practice
- Add a humidity field to the result.
- Disable the submit button while the request runs.
- Show a clear message when the city is not found.
Hands-on exercise
Build a weather card that:
1. Reads a city from an input.
2. Fetches data from /api/weather?city=...
3. Shows the temperature and condition.
4. Shows an error message if the request fails.
Recap
A data-driven page needs a clear flow: read input, show loading, fetch, render and recover from errors. Keep secrets on the server.
Example
const form = document.querySelector("#search-form");
const result = document.querySelector("#result");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const city = form.elements.city.value.trim();
if (!city) return;
result.textContent = "Loading…";
try {
const response = await fetch(`/api/weather?city=${encodeURIComponent(city)}`);
if (!response.ok) throw new Error("City not found");
const data = await response.json();
result.textContent = `${data.city}: ${data.temperature}°C, ${data.condition}`;
} catch (error) {
result.textContent = error.message;
}
});
Exercises
1. Reads a city from an input.
2. Fetches data from /api/weather?city=...
3. Shows the temperature and condition.
4. Shows an error message if the request fails.
Expected Output
A weather card that loads data or shows a clear error.