0

I'm creating a weather dashboard that updates every 5 seconds. I would like the user to be able to change the target city, and have the dashboard update with the new data. Problem is every time they input a new city, the previous data stays and it seems to be looping through all the inputs the user has made so far.

I would like the data to be updated after the user inputs a new city, rather than added. This is my code:

window.onload = function() {
    const api_key = "c7eedc2fa8594d69aa6122025212904";
    const inputCity = document.getElementById("inputCity");
    const getCity = document.querySelector("form");

    getCity.addEventListener("submit", e => {
        // Prevent the form from submission
        e.preventDefault();
        var inputVal = inputCity.value;
        var api_url = "http://api.weatherapi.com/v1/forecast.json?key=" + api_key + "&q=" + inputVal + "&days=3&aqi=no&alerts=no";
        // Get the dataset
        function refreshData() {
            fetch(api_url).then(response => {
                response.json().then(json => {
                        var dataset = json;
                        var output = formatResponse(dataset);
                    })
                    // Catch error - for example, the user doesn't input a valid city / postcode / country
                    .catch(error => console.log("not ok")); // TO BE IMPROVED
            })

        }

        refreshData(); // Display the dashboard immediately

        setInterval(refreshData, 5000); // And then refresh the dashboard every X milliseconds


    });

    function formatResponse(dataset) {

        console.log(dataset);

        // Current temp
        var currentTemp = [dataset.current.temp_c];
        console.log(currentTemp);
        document.getElementById("currentTempDsp").innerHTML = currentTemp + "°";

        // Current state icon
        var currentIcon = [dataset.current.condition.icon];
        console.log(currentIcon);
        document.getElementById("iconDsp").src = "http://" + currentIcon;

        // Current state text
        var currentText = [dataset.current.condition.text];
        console.log(currentText[0]);
        document.getElementById("currentStateDsp").innerHTML = currentText;

    }


}
        <form id="getCity" class="search">
            <label id="labelCity">Search for a city...</label></br>
            <input type="text" id="inputCity" class="inputCity" placeholder="Type city name here...">
            <button id="submitCity" type="submit" class="submitCity"><i class="fas fa-search"></i>Submit</button>
        </form>
            <div class="state">
                <h2 id="currentTempDsp"></h2>
                <img id="iconDsp"/>
                <span id="currentStateDsp"></span>
            </div>

        </div>
        
    </div>
ergoProxy
  • 93
  • 9
  • You’ll have to store a reference to the current interval in a variable, then clear out with `clearInterval()` before setting a new one. – esqew May 11 '21 at 12:17
  • Duplicate of [Replacing a setInterval timer in JS](https://stackoverflow.com/questions/37260781/replacing-a-setinterval-timer-in-js) – esqew May 11 '21 at 12:18
  • @esqew Thank you, I had tried doing that, but it doesn't work unfortunately :( – ergoProxy May 11 '21 at 12:22
  • Can you be a bit more specific about *why* the answers in the linked duplicate didn't meet your requirements (error messages, expected vs. actual behavior)? – esqew May 11 '21 at 12:27
  • @esqew It didn't change anything, as in I'm having the same problem. I stored the set interval in a variable (interval) and added clearInterval(interval); everywhere in the submit event listener, but nothing. Could you provide some code with how you would do it? – ergoProxy May 11 '21 at 12:33
  • When you stored the return value of `setInterval()` in a variable, was its value properly scoped (globally, outside the event handling function)? – esqew May 11 '21 at 12:59
  • @esqew I tried that now, but it's telling me that refreshData() is not defined so the dashboard isnt updating. – ergoProxy May 11 '21 at 13:08

1 Answers1

0

When you create an interval using setInterval() it continues to execute until the page is reloaded, navigated away from, or explicitly cleared using clearInterval(). Simply setting more intervals will not stop any previous ones from firing.

Use a globally-scoped variable to store the return value of setInterval() - check if it's set in the beginning of your submit event handler and clear it if it is.

A simplified example of how you could get this done:

const locations = [{
  temp: 73,
  conditions: 'Sunny'
}, {
  temp: 22,
  conditions: 'Mostly Cloudy'
}];

var currentInterval = null;

const updateTemp = locationData => {
  document.querySelector(".number").innerText = locationData.temp;
  document.querySelector(".conditions").innerText = locationData.conditions;
  console.log(`updated interface with temperature (${locationData.temp}) and conditions (${locationData.conditions}) data`);
}

[...document.querySelectorAll('.add-location')].forEach(button => {
  button.addEventListener('click', (e) => {
    // clear the interval
    if (currentInterval) {
      clearInterval(currentInterval);
      currentInterval = null;
      console.log('cleared currentInterval');
    }
    updateTemp(locations[parseInt(e.srcElement.dataset.loc)]);
    currentInterval = setInterval(function () {
      updateTemp(locations[parseInt(e.srcElement.dataset.loc)]);
    }, 2500);
  });
});
* {
  font-family: sans-serif;
}

.temp {
  font-size: 2em;
}

.conditions {
  font-style: italic;
}
<div class="temp">
  <span class="number">--</span>
  <span class="deg">&deg;</span>
</div>
<div class="conditions">--</div>
<div>
  <button class="add-location" data-loc="0">Add location 0</button>
  <button class="add-location" data-loc="1">Add location 1</button>
</div>
esqew
  • 42,425
  • 27
  • 92
  • 132