JSON Data not updating onChange()

Viewed 101

I'm trying to do a html page that contains a table of countries, #of cases, and #of deaths that on page load displays all countries with select tag to view just a single countries data. I'm having a problem with selecting options other than "All Countries" as if I select anything else, it doesn't return their data. Any help would be appreciated and I apologise in advance for my messy code

let countriesJSON = null // this will be loaded once in ajaxListAllCountries() and used in listAllStatsInCountry()
let totalCountries = []

async function ajaxListAllCountries() {
  let url = `covidData.json` /* name of the JSON file */

  try {
    const response = await fetch(url, {
      method: `POST`,
      headers: {
        'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
      },
    })

    updateWebpage(await response.json())
  } catch (error) {
    console.log('Fetch failed: ', error)
  }



  /* use the fetched data to change the content of the webpage */
  function updateWebpage(jsonData) {
    let uniqueCountries = []
    let countryCases = []
    let countryDeaths = []
   

    // save the list of countries to local memory
    countriesJSON = JSON.parse(JSON.stringify(jsonData))

    let countries = jsonData.records.map(country =>
      ({
        Country: country.countriesAndTerritories,
        Cases: country.cases,
        Deaths: country.deaths
      })
    )
    // get the list of unique countries
    let countryNames = countries.map(country => country.Country)
    uniqueCountries = Array.from(new Set(countryNames)).sort()
    uniqueCountries.unshift("All Countries") // add "All Countries" to the front of the array
    const sumCountryCases = (countries, name) => {
      let total = 0
      countries.forEach(cases => {
        if (cases.Country === name) {
          total += cases.Cases
        }
      })
      return total
    }
    for (let i = 0; i < uniqueCountries.length; i++) {
      countryCases[i] = sumCountryCases(countries, uniqueCountries[i])
    }

    const sumCountryDeaths = (countries, name) => {
      let total = 0
      countries.forEach(deaths => {
        if (deaths.Country === name) {
          total += deaths.Deaths
        }
      })
      return total
    }
    for (let i = 0; i < uniqueCountries.length; i++) {
      countryDeaths[i] = sumCountryDeaths(countries, uniqueCountries[i])
    }


    for (let i = 0; i < uniqueCountries.length; i++) {
      totalCountries[i] = {
        Country: uniqueCountries[i],
        Cases: countryCases[i],
        Deaths: countryDeaths[i]
      }
    }


    console.log(totalCountries)
    console.log(uniqueCountries)

    let htmlString = `<select id="countries" onChange="listAllStatsInCountry(this.value)">`

    uniqueCountries.map(country => {
      if (country !== "") {
        htmlString += `<option value = "${country}">${country}</option>`
      }
    })

    htmlString += `</select>`
    document.getElementById('countries').innerHTML = htmlString

    // list all countries when the webpage opens
    listAllStatsInCountry("All Countries")
  }
}


function listAllStatsInCountry(country) {

  let statsInCountry = null;

  if (country === "All Countries") {
    statsInCountry = totalCountries

  } else if (country === "No Country") {
    statsInCountry = totalCountries.filter(country => country.Country === "")
  } else {
    statsInCountry = totalCountries.filter(country => country.Country === country)
  }

  let htmlString = `<table id="countriesTable"><tr><th>Country</th><th>Cases</th><th>Deaths</th></tr>`

  statsInCountry.map(country => {
    if (country.Country !== "All Countries") {
      htmlString += `<tr>
                           <td>${country.Country}</td>
                           <td>${country.Cases}</td>
                           <td>${country.Deaths}</td>
                      </tr>`
    }
  })


  htmlString += `</table><br>${statsInCountry.length} records found.`
  document.getElementById('allCountries').innerHTML = htmlString
}
<html>

<head>
  <title>Global Covid-19 Statistics</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <script>
  </script>
</head>

<body onload="ajaxListAllCountries()">
  <div id="countries"></div>
  <div id="allCountries"></div>

</body>

</html>
EDIT - Added a small bit of sample data from the json file

{
  "records": [{
        "dateRep": "31/10/2020",
        "day": "31",
        "month": "10",
        "year": "2020",
        "cases": 157,
        "deaths": 4,
        "countriesAndTerritories": "Afghanistan",
        "geoId": "AF",
        "countryterritoryCode": "AFG",
        "popData2019": 38041757,
        "continentExp": "Asia",
        "Cumulative_number_for_14_days_of_COVID-19_cases_per_100000": "3.55398937"
      },
      {
        "dateRep": "17/05/2020",
        "day": "17",
        "month": "05",
        "year": "2020",
        "cases": 4,
        "deaths": 0,
        "countriesAndTerritories": "Estonia",
        "geoId": "EE",
        "countryterritoryCode": "EST",
        "popData2019": 1324820,
        "continentExp": "Europe",
        "Cumulative_number_for_14_days_of_COVID-19_cases_per_100000": "5.35921861"
      },
      {
        "dateRep": "16/01/2020",
        "day": "16",
        "month": "01",
        "year": "2020",
        "cases": 0,
        "deaths": 0,
        "countriesAndTerritories": "Estonia",
        "geoId": "EE",
        "countryterritoryCode": "EST",
        "popData2019": 1324820,
        "continentExp": "Europe",
        "Cumulative_number_for_14_days_of_COVID-19_cases_per_100000": "0"
      }

1 Answers

You don't need a POST request at all since you are simply GETing a file. Your code works fine otherwise as demonstrated here: http://plnkr.co/edit/sAUdQx7dUckGAOrC

Edit in response to OP's comment:

Both filters are incorrect in the listAllStatsInCountry() function. Currently the array filters are written:

statsInCountry = totalCountries.filter(country => country.Country === country)

In both cases the use of variable country as the arrow function parameter shadows the outer scope's variable with the same name. So the filter doesn't ever find any thing. To fix this change those filters parameter names to something else like this:

statsInCountry = totalCountries.filter(c => c.Country === country)

That will work. The Plunkr has been updated.

Change:

const response = await fetch(url, {
  method: `POST`,
  headers: {
    'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
  },
})

To:

const response = await fetch(url);`
Related