0

I've created list of list containing some data about countries (grouped by subregions, each country contains following data: name, capital, population and area). Now I would like to add ability to hide or show all the countries belonging to its subregion. For example after clicking on subregion North America all the countries belonging to NA should show up, or hide if they were shown up already. Right now all I can do is to show the whole list of subregions with all its countries and I am clueless how to add the ability of dropdown. I will be extremely grateful for help.

Below is source code of what i was able to do.

let div = document.createElement('div');
document.body.appendChild(div);
let ul = document.createElement('ul');

div.appendChild(ul);

async function f() {
    //fetching and sorting data by regions and subregions
    const res = await fetch("https://restcountries.com/v3.1/all");
    const data = await res.json();
    data.sort((a, b) => {
        if (a.region > b.region) return 1;
        else if (a.region < b.region) return -1
        else {
            if (a.subregion > b.subregion) return 1;
            else return -1;
        }
    })
    //count no of subregions and totals of subregion area and population data
    var prevSR = null;
    var cntSR = 0;
    var subregPop = [];
    var subregArea = [];
    var localPop = 0;
    var localArea = 0;
    for (const x of data) {
        if (prevSR != x.subregion) {
            cntSR += 1;
            prevSR = x.subregion;
            subregPop.push(localPop);
            subregArea.push(localArea);
            localArea = 0;
            localPop = 0;
        }
        localArea += x.area;
        localPop += x.population;
    }
    //loop to upload data to lists
    var i = 0
    prevSubregion = data[0].subregion;
    for (var a = 0; a < cntSR; a++) {
        //creating subregion
        let li = createSubregion(data[i].subregion, subregPop[a + 1], subregArea[a + 1]);
        let subOl = document.createElement('ol');

        while (prevSubregion == data[i].subregion) {
            //creating country
            prevSubregion = data[i].subregion;
            subLi = createCountry(data[i].name.common, data[i].capital, data[i].area, data[i].population);
            subOl.appendChild(subLi);
            i += 1;
        }
        prevSubregion = data[i].subregion;
        li.appendChild(subOl);
        ul.appendChild(li);
    }

}

function createSubregion(name, population, area) {
    var li = document.createElement("li");
    li.setAttribute("class", "subregion");

    var header = document.createElement("div");
    header.setAttribute("class", "subregion-header disp-flex");

    var nameDiv = document.createElement("div");

    var nameh2 = document.createElement("h2");
    nameh2.innerText = name;

    nameDiv.appendChild(nameh2);
    header.append(nameDiv);

    var emptyDiv = document.createElement("div");
    header.appendChild(emptyDiv);

    var populationDiv = document.createElement("div");
    var populationh2 = document.createElement("h3");
    populationh2.innerText = population;

    populationDiv.appendChild(populationh2);
    header.append(populationDiv);

    var areaDiv = document.createElement("div");
    var areah2 = document.createElement("h3");
    areah2.innerText = area;

    areaDiv.appendChild(areah2);
    header.append(areaDiv);

    li.appendChild(header);
    return li;
}

function createCountry(name, capital, area, population) {
    var country = document.createElement("li");
    country.setAttribute("class", "country disp-flex")

    var namediv = document.createElement("div");
    var nameh4 = document.createElement("h4");
    nameh4.innerText = name;
    namediv.appendChild(nameh4);
    country.appendChild(namediv);

    var capitaldiv = document.createElement("div");
    var capitalh4 = document.createElement("h4");
    capitalh4.innerText = capital;
    capitaldiv.appendChild(capitalh4);
    country.appendChild(capitaldiv);

    var popdiv = document.createElement("div");
    var poph4 = document.createElement("h4");
    poph4.innerText = population;
    popdiv.appendChild(poph4);
    country.appendChild(popdiv);

    var areadiv = document.createElement("div");
    var areah4 = document.createElement("h4");
    areah4.innerText = area;
    areadiv.appendChild(areah4);
    country.appendChild(areadiv);


    return country;
}

f();
body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background-color: aliceblue;
    font-family: 'Open Sans', Arial;
    font-size: 18px;
}
header{
    display:flex;
    justify-content: space-between;
    padding: 22px 0;
    color:rgb(5, 5, 5);
}
ul {
    list-style: none;
    list-style-type: none;
    outline: 2px solid #ddd;
    padding: 1rem 2rem;
    border-radius: 0.5rem;
    list-style-position: inside;
    color: blue;
}

ul ol { 
    color: rgb(197, 105, 18);
    list-style: none;
    list-style-type: none;
    font-size: .9em;
    margin: 0.4rem 0;
}
.country{
    display: flex;
    justify-content: space-between;
}
.disp-flex{
    display:flex;
    justify-content: space-between;
}

.disp-flex > div{
    width:23%;
    padding:15px 0px;
}


.subregion-header>div:nth-child(1){
    position: relative;
    left:30px;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <main class="container">
        <header>
            <div id="name">
                <h1>Name-</h1>
            </div>
            <div id="capital">
                <h1>Capital-</h1>
            </div>
            <div id="population">
                <h1>Population-</h1>
            </div>
            <div id="area">
                <h1>Area</h1>
            </div>

        </header>

        <script src="script.js"></script>
    </main>
</body>

</html>

Second thing, but not as important as first, I would also need to add feature of sorting and filtering each column after clicking div element on the very top. So for example after clicking AREA, on the header section, countries should be sorted by their area. And the filter option allowing to show only countries that, for example, start with letter 'A'.

0

1 Answer 1

1

You can group the subregions first like,

const subRegions = data.reduce((r, a) => {
    r[a.subregion] = r[a.subregion] || [];
    r[a.subregion].push(a);
    return r;
}, {});

And then create a select element and inject the text and value respectively.

Then handle the onchange and get the slected subregion data instead of all at once like subRegions[subRegionName] .

Forked example:

let div = document.createElement('div');
document.body.appendChild(div);
let ul = document.createElement('ul');

div.appendChild(ul);

async function f() {
    //fetching and sorting data by regions and subregions
    const res = await fetch("https://restcountries.com/v3.1/all");
    const data = await res.json();
    data.sort((a, b) => {
        if (a.region > b.region) return 1;
        else if (a.region < b.region) return -1
        else {
            if (a.subregion > b.subregion) return 1;
            else return -1;
        }
    });
    
    const container = document.getElementById('container');
    const select = document.createElement('select');
    const olWrapper = document.getElementById('listWrapper');   
    const subRegionWrapper = document.getElementById('subRegionWrapper');

    const subRegions = data.reduce((r, a) => {
        r[a.subregion] = r[a.subregion] || [];
        r[a.subregion].push(a);
        return r;
    }, {});

   const dropdownValues = Object.keys(subRegions);
    const firstOption = document.createElement('option');
     firstOption.value = -1;
     firstOption.text = "Select a Subregion";
     select.appendChild(firstOption);
    dropdownValues.forEach(item => {
      const option = document.createElement('option');
      option.value = item;
      option.text = item;
      select.appendChild(option);
    });
  
 container.appendChild(select);

 select.onchange = (e) => {
   olWrapper.innerHTML = '';
   const subRegionName = e.target.value;
   const filteredValues = subRegions[subRegionName];
   const totalArea = filteredValues.reduce((acc, curr) => acc+curr.area,0);
   const totalPopulation = filteredValues.reduce((acc, curr) => acc+curr.population,0);
   const li = createSubregion(subRegionName, totalPopulation, totalArea);
   ul.innerHTML = '';
   ul.appendChild(li);
   subRegionWrapper.appendChild(ul);

    filteredValues.forEach(item => {
      const subLi = createCountry(item.name.common, item.capital, item.area, item.population);
      const subOl = document.createElement('ol');
      subOl.appendChild(subLi);
      olWrapper.appendChild(subOl);
    })     
 };

}

function createSubregion(name, population, area) {
    var li = document.createElement("li");
    li.setAttribute("class", "subregion");

    var header = document.createElement("div");
    header.setAttribute("class", "subregion-header disp-flex");

    var nameDiv = document.createElement("div");

    var nameh2 = document.createElement("h2");
    nameh2.innerText = name;

    nameDiv.appendChild(nameh2);
    header.append(nameDiv);

    var emptyDiv = document.createElement("div");
    header.appendChild(emptyDiv);

    var populationDiv = document.createElement("div");
    var populationh2 = document.createElement("h3");
    populationh2.innerText = population;

    populationDiv.appendChild(populationh2);
    header.append(populationDiv);

    var areaDiv = document.createElement("div");
    var areah2 = document.createElement("h3");
    areah2.innerText = area;

    areaDiv.appendChild(areah2);
    header.append(areaDiv);

    li.appendChild(header);
    return li;
}

function createCountry(name, capital, area, population) {
    var country = document.createElement("li");
    country.setAttribute("class", "country disp-flex")

    var namediv = document.createElement("div");
    var nameh4 = document.createElement("h4");
    nameh4.innerText = name;
    namediv.appendChild(nameh4);
    country.appendChild(namediv);

    var capitaldiv = document.createElement("div");
    var capitalh4 = document.createElement("h4");
    capitalh4.innerText = capital;
    capitaldiv.appendChild(capitalh4);
    country.appendChild(capitaldiv);

    var popdiv = document.createElement("div");
    var poph4 = document.createElement("h4");
    poph4.innerText = population;
    popdiv.appendChild(poph4);
    country.appendChild(popdiv);

    var areadiv = document.createElement("div");
    var areah4 = document.createElement("h4");
    areah4.innerText = area;
    areadiv.appendChild(areah4);
    country.appendChild(areadiv);


    return country;
}

f();
body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background-color: aliceblue;
    font-family: 'Open Sans', Arial;
    font-size: 18px;
}
header{
    display:flex;
    justify-content: space-between;
    padding: 22px 0;
    color:rgb(5, 5, 5);
}
ul {
    list-style: none;
    list-style-type: none;
    outline: 2px solid #ddd;
    padding: 1rem 2rem;
    border-radius: 0.5rem;
    list-style-position: inside;
    color: blue;
}

ul ol { 
    color: rgb(197, 105, 18);
    list-style: none;
    list-style-type: none;
    font-size: .9em;
    margin: 0.4rem 0;
}
.country{
    display: flex;
    justify-content: space-between;
}
.disp-flex{
    display:flex;
    justify-content: space-between;
}

.disp-flex > div{
    width:23%;
    padding:15px 0px;
}


.subregion-header>div:nth-child(1){
    position: relative;
    left:30px;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <main class="container">
        <header>
            <div id="name">
                <h1>Name-</h1>
            </div>
            <div id="capital">
                <h1>Capital-</h1>
            </div>
            <div id="population">
                <h1>Population-</h1>
            </div>
            <div id="area">
                <h1>Area</h1>
            </div>

        </header>

      
      <div id="container"></div>
      <div id="subRegionWrapper"> </div>
      <div id="listWrapper"></div>
     </script>
    </main>
</body>

</html>

Update:

Here is the updated version with each sub region is grouped as an accordion and on toggle, the respective countries under the sub region were displayed..

let div = document.createElement('div');
document.body.appendChild(div);
let ul = document.createElement('ul');

div.appendChild(ul);

async function f() {
    //fetching and sorting data by regions and subregions
    const res = await fetch("https://restcountries.com/v3.1/all");
    const data = await res.json();
    data.sort((a, b) => {
        if (a.region > b.region) return 1;
        else if (a.region < b.region) return -1
        else {
            if (a.subregion > b.subregion) return 1;
            else return -1;
        }
    });
    
    const container = document.getElementById('container');
    const accordion = document.createElement('div');
    const olWrapper = document.getElementById('listWrapper');   
    const subRegionWrapper = document.getElementById('subRegionWrapper');

    const subRegions = data.reduce((r, a) => {
        r[a.subregion] = r[a.subregion] || [];
        r[a.subregion].push(a);
        return r;
    }, {});

   const dropdownValues = Object.entries(subRegions);
    dropdownValues.forEach(subRegion => {
      const accordionWrapper = document.createElement('div');
      const panel = document.createElement('div');
      panel.classList.add('panel');
      accordionWrapper.classList.add('accordion');

      const totalArea = subRegion[1].reduce((acc, curr) => acc+curr.area,0);
      const totalPopulation = subRegion[1].reduce((acc, curr) => acc+curr.population,0);
      const li = createSubregion(subRegion[0], totalPopulation, totalArea);

      accordionWrapper.appendChild(li);
      accordion.appendChild(accordionWrapper);

      subRegion[1].forEach(item => {
          const subLi = createCountry(item.name.common, item.capital, item.area, item.population);
          const subOl = document.createElement('ol');
          subOl.appendChild(subLi);
          panel.appendChild(subOl);
          accordion.appendChild(panel);
      });

     accordionWrapper.addEventListener('click', function() {
        this.classList.toggle("active");
        const panel = this.nextElementSibling;
        if (panel.style.display === "block") {
          panel.style.display = "none";
        } else {
          panel.style.display = "block";
        }
     });
    });
  
  container.appendChild(accordion);
}

function createSubregion(name, population, area) {
    var li = document.createElement("li");
    li.setAttribute("class", "subregion");

    var header = document.createElement("div");
    header.setAttribute("class", "subregion-header disp-flex");

    var nameDiv = document.createElement("div");

    var nameh2 = document.createElement("h2");
    nameh2.innerText = name;

    nameDiv.appendChild(nameh2);
    header.append(nameDiv);

    var emptyDiv = document.createElement("div");
    header.appendChild(emptyDiv);

    var populationDiv = document.createElement("div");
    var populationh2 = document.createElement("h3");
    populationh2.innerText = population;

    populationDiv.appendChild(populationh2);
    header.append(populationDiv);

    var areaDiv = document.createElement("div");
    var areah2 = document.createElement("h3");
    areah2.innerText = area;

    areaDiv.appendChild(areah2);
    header.append(areaDiv);

    li.appendChild(header);
    return li;
}

function createCountry(name, capital, area, population) {
    var country = document.createElement("li");
    country.setAttribute("class", "country disp-flex")

    var namediv = document.createElement("div");
    var nameh4 = document.createElement("h4");
    nameh4.innerText = name;
    namediv.appendChild(nameh4);
    country.appendChild(namediv);

    var capitaldiv = document.createElement("div");
    var capitalh4 = document.createElement("h4");
    capitalh4.innerText = capital;
    capitaldiv.appendChild(capitalh4);
    country.appendChild(capitaldiv);

    var popdiv = document.createElement("div");
    var poph4 = document.createElement("h4");
    poph4.innerText = population;
    popdiv.appendChild(poph4);
    country.appendChild(popdiv);

    var areadiv = document.createElement("div");
    var areah4 = document.createElement("h4");
    areah4.innerText = area;
    areadiv.appendChild(areah4);
    country.appendChild(areadiv);


    return country;
}

f();
body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background-color: aliceblue;
    font-family: 'Open Sans', Arial;
    font-size: 18px;
}
header{
    display:flex;
    justify-content: space-between;
    padding: 22px 0;
    color:rgb(5, 5, 5);
}
ul {
    list-style: none;
    list-style-type: none;
    outline: 2px solid #ddd;
    padding: 1rem 2rem;
    border-radius: 0.5rem;
    list-style-position: inside;
    color: blue;
}

ul ol { 
    color: rgb(197, 105, 18);
    list-style: none;
    list-style-type: none;
    font-size: .9em;
    margin: 0.4rem 0;
}
.country{
    display: flex;
    justify-content: space-between;
}
.disp-flex{
    display:flex;
    justify-content: space-between;
}

.disp-flex > div{
    width:23%;
    padding:15px 0px;
}


.subregion-header>div:nth-child(1){
    position: relative;
    left:30px;
}

.accordion {
  background-color: #eee;
  color: #444;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
  transition: 0.4s;
  margin: 15px 2px;
}

.accordion li {
  list-style-type: none;
}

.active, .accordion:hover {
  background-color: #ccc; 
}

.panel {
  padding: 0 18px;
  display: none;
  background-color: white;
  overflow: hidden;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <main class="container">
        <header>
            <div id="name">
                <h1>Name-</h1>
            </div>
            <div id="capital">
                <h1>Capital-</h1>
            </div>
            <div id="population">
                <h1>Population-</h1>
            </div>
            <div id="area">
                <h1>Area</h1>
            </div>

        </header>

      
      <div id="container"></div>
      <div id="subRegionWrapper"> </div>
      <div id="listWrapper"></div>
     </script>
    </main>
</body>

</html>

Sign up to request clarification or add additional context in comments.

10 Comments

OK, that's really nice and works great. But I would need this to behave like in the picture linked here:codehim.com/menu/… So that you could open couple subregions at same time. Of course having different subregions instead of profile, message, settings etc.
@fantomx775, See the updated answer along with example.
it is looking really well, thank You. Would it be possible to add ability of sorting and filtering as well? For example clicking on area in the header section would sort the countries by area, and then clicking on name it would sort it by areas and names because both were clicked. I mean using different sorting and filtering options at same time. Filtering option could allow to show only countries matching expression in filter, so for example typing "Eth" in name filter should show only Ethiopia in Eastern Africa and typing "Par" in capitals should show France in Western Europe.
@fantomx775, This is out of scope of your current question. If you need additional things then raise a new question for that. Happy coding!
@fantomx775, Please accept the answer if it resolves your issue in this question.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.