Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Weather Project</title>
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"
integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 offset-md-3 text-center">
<div class="page-header mt-5">
<h1>Weather Project</h1>
<hr />
</div>

<form class="search-form mt-5">
<div class="form-group">
<div class="row">
<div class="col-md-9">
<input
type="text"
id="search-query"
class="form-control"
placeholder="Enter City Name Here"
required
/>
</div>
<div class="col-md-3">
<button
type="button"
id="search"
class="btn btn-primary search"
>
Search
</button>
</div>
</div>
</div>
</form>

<div class="current-weather row mt-5"></div>
</div>
</div>
<div class="forecast row mt-5 text-center"></div>
</div>
<script src="main.js" type="text/javascript"></script>
</body>
</html>
139 changes: 139 additions & 0 deletions main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
const searchButton = document.getElementById("search");
// Weekdays listed twice to account for overlap
const days = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];

searchButton.addEventListener("click", function () {
const userSearch = document.getElementById("search-query").value;

if (
!document.getElementById("search-query").checkValidity() ||
userSearch.trim().length === 0
) {
alert("Please enter the name of a city");
} else {
fetchWeatherData(userSearch);
}

document.getElementById("search-query").value = "";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for readability, you can extract this to a separate function like:

Suggested change
document.getElementById("search-query").value = "";
const resetSearchInput() => {
document.getElementById("search-query").value = "";
}

});

const searchLoading = () => {
searchButton.disabled = true;
searchButton.innerHTML = `<i class="fa fa-spinner fa-spin"></i>Loading
`;
};

const searchDone = () => {
searchButton.disabled = false;
searchButton.innerHTML = "Search";
};

const fetchWeatherData = (city) => {
const url = `https://api.openweathermap.org/data/2.5/forecast?q=${city}&appid=a01dd8f2b7b0fd48756b05d7cb1e2fe5`;

searchLoading();

fetch(url, {
method: "GET",
dataType: "json",
})
.then((data) => data.json())
.then((data) => {
displayWeatherData(data);
searchDone();
})
.catch(handleError);
};

fetchWeatherData("Charlotte");

const displayWeatherData = (data) => {
displayCurrentWeather(data);
displayForecast(data);
};

const displayCurrentWeather = (data) => {
document.querySelector(".current-weather").replaceChildren();
const fahrenheitTemp = convertKelvinToFahrenheit(data.list[0].main.temp);
const iconURL = `https://openweathermap.org/img/wn/${data.list[0].weather[0].icon}@2x.png`;

const template = `
<div class="col-md-6 justify-center">
<h2>${fahrenheitTemp}&deg</h2>
<h3 id="city">${data.city.name}</h3>
<h4 id="current-condition">${data.list[0].weather[0].main}</h4>
</div>
<div class="col-md-6">
<img
src= "${iconURL}"
/>
</div>`;

document
.querySelector(".current-weather")
.insertAdjacentHTML("beforeend", template);
};

const displayForecast = (data) => {
document.querySelector(".forecast").replaceChildren();

// Forecast data is stored in three hour intervals. This fetches the data every 8 intervals, or 24 hours
const dailyIntervals = [7, 15, 23, 31, 39];
const fiveDayForecast = dailyIntervals.map((interval) => data.list[interval]);

const date = new Date();

fiveDayForecast.forEach((day) => {
const index = fiveDayForecast.indexOf(day);
const forecastIconURL = `https://openweathermap.org/img/wn/${day.weather[0].icon}@2x.png`;
const forecastTemplate = `
<div class="col-md-2 justify-center p-5 border" id="${index}">
<h5 id="day-one-condition">${day.weather[0].main}</h5>
<h5 id="day-one-temp">${convertKelvinToFahrenheit(day.main.temp)}&deg</h5>
<img
id="day-one-icon"
src="${forecastIconURL}"
/>
<h6 id="day-one">${days[date.getDay() + (index + 1)]}</h6>
</div>`;

document
.querySelector(".forecast")
.insertAdjacentHTML("beforeend", forecastTemplate);
});
document.getElementById(`${0}`).classList.add("offset-md-1");
};

const convertKelvinToFahrenheit = (deg) => {
return Math.round((deg - 273) * 1.8 + 32);
};

function handleError(error) {
if (error instanceof TypeError) {
alert(`Oops. Something went wrong.
Please check that:
- You have entered a valid city
- You are connected to the interent`);
} else {
alert(
`Oops. Looks like something went wrong on our end.
ERROR: ${error}`
);
}
searchDone();
}
18 changes: 18 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.current-weather img {
max-width: 150px;
}

.forecast img {
max-width: 50px;
margin: 0px auto;
}

.justify-center {
display: flex;
flex-direction: column;
justify-content: center;
}

.border {
border: 1px solid black;
}