-2

I'm using the openweathermap.org API, and am using javascript to fetch the data, then post to HTML. I have two javascript functions. One function for getting the current weather is working really well - the second function is pulling the 5 day forecast. I have gotten to the point where I can pull the data, but I need to loop through that data and post to HTML. Here's the function:

function getForecast() {
    let forecast_icon = document.getElementById("forecast_icon");
    let forecast_temperature = document.getElementById("forecast_temperature");

    let api = "https://api.openweathermap.org/data/2.5/weather";
    let apiKey = "API KEY";

    location.innerHTML = "Locating...";

    navigator.geolocation.getCurrentPosition(success, error);

    function success(position) {
        latitude = position.coords.latitude;
        longitude = position.coords.longitude;

        let url = api + "?lat=" + latitude + "&lon=" + longitude + "&appid=" + apiKey + "&units=imperial";

        fetch(url)
            .then(response => response.json())
            .then(forecast => {
                console.log(forecast);

                let temp = forecast.main.temp;
                forecast_temperature.innerHTML = Math.round(temp) + "°F";
                let icon = forecast.weather[0].icon;
                forecast_icon.innerHTML = '<img src="http://openweathermap.org/img/wn/' + icon + ".png" + '"/>';
            });
    }

    function error() {
        location.innerHTML = "Unable to retrieve your location";
    }
}

getForecast();

Here's the HTML - it's quite simple:

<ul>
  <li>
    <div id='forecast_icon'></div>
    <div class='temperature-sensor-day' id='forecast_temperature'></div>
  </li>
</ul>

I'm not sure how to loop through the data and post each result to the HTML. I'll keep searching but would appreciate some guidance.

Edit:

I need to loop through the output of the API calls and post that data into the HTML shown above.

I tried working with "promises". I saw this in my searches:

for (url in urls){
    time = getData(urls[url])
    console.log(time)
    ttTimes.push(time)
};

I tried substituting my values but since this one uses two url's I couldn't work out how to make it work.

I've also seen different types of loops so I'm getting confused on the best way to do this.

Below is a picture of what it looks like. You can see that only one of the five days are populating. Hopefully that helps visualize the problem.

weather app

Steve Shead
  • 121
  • 8
  • 1
    You aren't supplying sample data from the API call, which makes it hard to guess what data structure you want help looping over. – Marc Nov 22 '20 at 03:23
  • 1
    You don't show any attempt at trying to step through the data and maybe try editing that in. Your code calls the api. I'm on my phone but a good start is look at map and for the dontenv I posted a question about it when I got stuck with it: https://stackoverflow.com/questions/57213162/why-are-my-custom-process-env-not-working-within-dotenv – DᴀʀᴛʜVᴀᴅᴇʀ Nov 22 '20 at 03:25
  • @DᴀʀᴛʜVᴀᴅᴇʀ - I've tried looking up "promises" as well as using a foreach loop but am trying to find out where the loop belongs, let alone how to form it. – Steve Shead Nov 22 '20 at 03:26
  • 1
    Its better to post that in and explain that because right now its completely missing. – DᴀʀᴛʜVᴀᴅᴇʀ Nov 22 '20 at 03:27
  • 1
    I have deleted and/or edited a bunch of comments here to remove discussion of votes. **Please do not discuss votes in comments.** Votes are anonymous, and no one is ever expected to give a reason for their votes, whether up or down. – Cody Gray - on strike Nov 22 '20 at 12:05
  • 1
    To be blunt, Steve, the answer to your question about where you can chat with me about this is "nowhere". It isn't something that is really up for debate or discussion. It's just site policy. You say "downvoting without reason", but that's not the case. The downvoters *have* a reason. They just chose not to leave a comment. That's a different thing. The reason is given on the tooltip for the downvote arrow. Constructive criticism is, I agree, welcome, but it is *optional*. Lashing out at downvoters is *not* welcome. See also: [the relevant FAQ on Meta](https://meta.stackoverflow.com/q/357436) – Cody Gray - on strike Nov 24 '20 at 21:57

1 Answers1

1

You're just about there. The data you're looking for is in the list array of the API's response, documented here. You've just gotta loop through the list array, creating the HTML elements for each datum you wish to display, and appending to the DOM as you go.

Note that I'm dynamically making the HTML elements to insert the data into, so you won't need the current ones you have in your HTML document.

fetch(url)
    .then(response => response.json())
    .then(forecast => {

        // For each day, we'll loop through and add it to the DOM:
        forecast.list.forEach(day => {

            // Create a new element to hold each day's data in the DOM:
            const dayContainer = document.createElement('div')

            // Create an element to hold the temp data:
            const temp = day.main.temp;
            const tempElem = document.createElement('div')
            tempElem.innerText = Math.round(temp) + '°F'
            dayContainer.appendChild(tempElem)

            // Create an image element to hold the icon:
            const icon = day.weather[0].icon;
            const iconElem = document.createElement('img')
            iconElem.src = 'http://openweathermap.org/img/wn/' + icon + '.png'
            dayContainer.appendChild(iconElem)

            // Add the result to the DOM:
            document.body.appendChild(dayContainer)
        })
    })

Note that at the end I'm appending to the document.body. You may want to append to a different element, deeper in your DOM's hierarchy.

jmealy
  • 583
  • 1
  • 5
  • 14
  • I have a function for the weather itself - looks like this. The other one returns 5 days forecast. fetch(url) .then(response => response.json()) .then(data => { console.log(data); let temp = data.main.temp; temperature.innerHTML = Math.round(temp) + "°"; weather_icon.innerHTML = ''; location.innerHTML = data.name; description.innerHTML = data.weather[0].main; }); – Steve Shead Nov 22 '20 at 03:43
  • I kinda see where that is going - but - there is only one URL. That one URL pulls the data.The URL is formed here: let url = api + "?lat=" + latitude + "&lon=" + longitude + "&appid=" + apiKey + "&units=imperial"; - are you saying I need more than one URL? – Steve Shead Nov 22 '20 at 04:02
  • I've updated my answer to account for the update to your question. Promises are pretty rad, but they're also a lot to break into. Once you get comfortable with `Promise.all` and `.then`s, you should check out the [`async` and `await`](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await) syntax. It takes out a lot of the nesting caused by a ton of `.then`s, and keeps everything in the same high-level scope. – jmealy Nov 22 '20 at 04:02
  • Ah - maybe not. I thought you were saying you had multiple URLs you needed to query. Looking through the openweathermap API, I'm not seeing where you'd get multiple days back in a single response. Are you seeing this, and if so, can you link to it? – jmealy Nov 22 '20 at 04:08
  • Sure - here's the API I'm using: https://openweathermap.org/forecast5 - I had this working using PHP but it required a form to make it work, and it was messy. I thought javascript would be cleaner! – Steve Shead Nov 22 '20 at 04:11
  • In the future, I'd recommend posting the API you're working from in your question. Would have saved a lot of time here, as openweather has a lot of different APIs. I've revised my answer again to address your use case. – jmealy Nov 22 '20 at 04:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/224912/discussion-between-jmealy-and-steve-shead). – jmealy Nov 22 '20 at 04:30