1

This code snippet works well, but I want to know the logic behind if statement in updateList function? I know why I get all countries when the select value is to all, but when I chose other value in a select list like Oceania, I get just countries from that region. How that simple logical or operator can filter the rest of the countries and return just a specific region? I'd appreciate if someone can explain me step by step how that whole updateList function works?

const regionMenu = document.querySelector('#regionMenu');
const result = document.querySelector('.result');
const countryUrl = 'https://restcountries.eu/rest/v2/all';
let countries;

fetch(countryUrl)
    .then(response => response.json())
    .then(json => {
        countries = json;
        // console.log(countries);
        updateList();
    })
    .catch(err => console.log(err));

function updateList() {
    let output = '';
    for(let i = 0; i < countries.length; i++) {
        if(regionMenu.value === 'all' || regionMenu.value === countries[i].region) {
          output += `
          <div>
            <img src=${countries[i].flag} width="160px" height="80px">
            <ul>
              <li> Name: ${countries[i].name}</li>
              <li> Population: ${countries[i].population}</li>
              <li> Region: ${countries[i].region}</li>
              <li> Capital: ${countries[i].capital}</li>
            </ul>
          </div>
        `;
        }
    }
    result.innerHTML = output;
}

regionMenu.addEventListener('change', updateList);
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <header>
        <h3>Where in the world?</h3>
        <i class="fas fa-moon">Dark Mode</i>
    </header>
    <nav>
        <!-- Search input -->
        <div class="search">
            <i class="fas fa-search"></i>
            <input type="text" placeholder="Search for a country" id="searchInput">
        </div>
    </nav>
    <main>
        <!-- Filter Countries -->
        <select name="Filter by Region" id="regionMenu">
            <option value="all">Filter by Region</option>
            <option value="Africa">Africa</option>
            <option value="Americas">Americas</option>
            <option value="Asia">Asia</option>
            <option value="Europe">Europe</option>
            <option value="Oceania">Oceania</option>
        </select>
        <div class="result">

        </div>
    </main>

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

</html>
Mario93
  • 55
  • 7

4 Answers4

3

You're probably being misled by the fact that that code is using map incorrectly. First, though, answering your actual question:

How that simple logical or operator can filter the rest of the countries and return just specific region?

If the condition is false, the map callback doesn't do anything. If the condition is true, it appends to the output variable.

So what's that about using map incorrectly? Sadly, someone out there is teaching map as a general purpose iterator for arrays. It isn't. map creates a new array from the return values it gets from its callback. If you're not using that new array, map is quite simply the wrong tool to use — use forEach or for-of or any of several other ways to loop through an array.

But since that code is using map, you probably thought map was doing something other than just looping through the array. It isn't, it's just been used incorrectly.

As I say, based on code seen on Stack Overflow in the last ~18 months or so, someone must be actively teaching this misuse of map, which is unfortunate.

Here are some examples of ways you could update updateList --

Using forEach:

function updateList() {
    let output = '';
    countries.forEach(country => {
        if (regionMenu.value === 'all' || regionMenu.value === country.region) {
          output += `
          <div>
            <img src=${country.flag} width="160px" height="80px">
            <ul>
              <li> Name: ${country.name}</li>
              <li> Population: ${country.population}</li>
              <li> Region: ${country.region}</li>
              <li> Capital: ${country.capital}</li>
            </ul>
          </div>
        `;
        }
    });
    result.innerHTML = output;
}

Using for-of:

function updateList() {
    let output = '';
    for (const country of countries) {
        if (regionMenu.value === 'all' || regionMenu.value === country.region) {
          output += `
          <div>
            <img src=${country.flag} width="160px" height="80px">
            <ul>
              <li> Name: ${country.name}</li>
              <li> Population: ${country.population}</li>
              <li> Region: ${country.region}</li>
              <li> Capital: ${country.capital}</li>
            </ul>
          </div>
        `;
        }
    }
    result.innerHTML = output;
}

Using map correctly by always returning a meaningful value and using .join("") on the resulting array:

function updateList() {
    result.innerHTML = countries.map(country => {
        if (regionMenu.value === 'all' || regionMenu.value === country.region) {
          return `
          <div>
            <img src=${country.flag} width="160px" height="80px">
            <ul>
              <li> Name: ${country.name}</li>
              <li> Population: ${country.population}</li>
              <li> Region: ${country.region}</li>
              <li> Capital: ${country.capital}</li>
            </ul>
          </div>
        `;
        }
        return "";
    }).join("");
}

Using filter, then map, then join:

function updateList() {
    result.innerHTML = countries.filter(
        country => regionMenu.value === 'all' || regionMenu.value === country.region
    ).map(country => `
          <div>
            <img src=${country.flag} width="160px" height="80px">
            <ul>
              <li> Name: ${country.name}</li>
              <li> Population: ${country.population}</li>
              <li> Region: ${country.region}</li>
              <li> Capital: ${country.capital}</li>
            </ul>
          </div>
        `
    ).join("");
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    Thanks man for this useful information, I'm relatively new to the javascript and sometimes is hard to catch those non visible errors, I replaced it with a for loop. – Mario93 Dec 11 '19 at 14:08
1

Every time the updateList() function is invoked, it creates a new empty output variable. Then with the map it iterates through the country objects. For each object it examines wether the select input's value is all, or the selected option's value is the same as the current element's region.

If all is selected then the if condition evaluates true to all elements thus adding each to the output variable.

If it's not all, but the selected value is equivalent the the current object's region then the current object is a match and the div with the object's necessary keys is added to the output variable.

In the end this output variable is appended to the result div.

B. Ma
  • 221
  • 2
  • 15
1

Image the countries structure is an array with the object only with region and name.

For example, I have this array:

const countries = [
    {region: "oceania", name: "australia"},
    {region: "oceania", name: "fiji"},
    {region: "oceania", name: "Samoa"},
    {region: "south america", name: "peru"},
    {region: "south america", name: "brazil"},
    {region: "south america", name: "argentina"},
];

Now you will map all the array each by each element with the if statement who said:

  1. If regionMenu.value is all, I will print the current country
  2. If regionMenu.value is the same of the contry.region, I will print the current country

The or operator || said only 1 part will be true to pass.

If you select the regionMenu.value as "all", all the countries will be pass in the first section of the conditional (1).

Otherwise, if you select another value like "oceania" the first part always be false oceania === all => False (1). So the filter will be depends of the second part (2):

australia: oceania === oceania (True)
fiji: oceania === oceania (True)
Samoa: oceania === oceania (True)
peru: oceania === south america (False)
brazil: oceania === south america (False)
argentina: oceania === south america (False)

Res: [australia, fiji, Samoa].

As another example, if the value of regionMenu.value is "south america" the results will be:

australia: south america === oceania (False)
fiji: south america === oceania (False)
Samoa: south america === oceania (False)
peru: south america === south america (True)
brazil: south america === south america (True)
argentina: south america === south america (True)

Res: [peru, brazil, argentina].
jtwalters
  • 1,024
  • 7
  • 25
1

Once again, thank you everybody for taking your time and providing me with great information. Usually this programming world can be very negative, but I'm glad that I joined this great community. Have a great day everybody!

Mario93
  • 55
  • 7