1
\$\begingroup\$

I've created a small project that fetches data from a 'countries' API and works around with it to display the 'top 10 most populated countries' & 'top 10 most spoken languages'. I kindly wish if this code can be reviewed for improvements since I don't have anyone who can review my code.. :(

I mostly care about the js part so if this can be scrutinized and returned with feedback regarding all of the criteria to write correct and beautiful js and if I met that criteria. thanks in advance :)

"use strict";
const countries_data = [
  {
    name: "Afghanistan",
    capital: "Kabul",
    languages: ["Pashto", "Uzbek", "Turkmen"],
    population: 40218234,
    flag: "https://upload.wikimedia.org/wikipedia/commons/5/5c/Flag_of_the_Taliban.svg",
    region: "Asia",
    area: 652230,
  },
  {
    name: "Åland Islands",
    capital: "Mariehamn",
    languages: ["Swedish"],
    population: 28875,
    flag: "https://flagcdn.com/ax.svg",
    region: "Europe",
    area: 1580,
  },
  {
    name: "Albania",
    capital: "Tirana",
    languages: ["Albanian"],
    population: 2837743,
    flag: "https://flagcdn.com/al.svg",
    region: "Europe",
    area: 28748,
  },
  {
    name: "Algeria",
    capital: "Algiers",
    languages: ["Arabic"],
    population: 43851043,
    flag: "https://flagcdn.com/dz.svg",
    region: "Africa",
    area: 2381741,
  },
  {
    name: "American Samoa",
    capital: "Pago Pago",
    languages: ["English", "Samoan"],
    population: 55197,
    flag: "https://flagcdn.com/as.svg",
    region: "Oceania",
    area: 199,
  },
  {
    name: "Andorra",
    capital: "Andorra la Vella",
    languages: ["Catalan"],
    population: 77265,
    flag: "https://flagcdn.com/ad.svg",
    region: "Europe",
    area: 468,
  },
  {
    name: "Angola",
    capital: "Luanda",
    languages: ["Portuguese"],
    population: 32866268,
    flag: "https://flagcdn.com/ao.svg",
    region: "Africa",
    area: 1246700,
  },
  {
    name: "Anguilla",
    capital: "The Valley",
    languages: ["English"],
    population: 13452,
    flag: "https://flagcdn.com/ai.svg",
    region: "Americas",
    area: 91,
  },
  {
    name: "Antarctica",
    languages: ["English", "Russian"],
    population: 1000,
    flag: "https://flagcdn.com/aq.svg",
    region: "Polar",
    area: 14000000,
  },
  {
    name: "Antigua and Barbuda",
    capital: "Saint John's",
    languages: ["English"],
    population: 97928,
    flag: "https://flagcdn.com/ag.svg",
    region: "Americas",
    area: 442,
  },
  {
    name: "Argentina",
    capital: "Buenos Aires",
    languages: ["Spanish", "Guaraní"],
    population: 45376763,
    flag: "https://flagcdn.com/ar.svg",
    region: "Americas",
    area: 2780400,
  },
  {
    name: "Armenia",
    capital: "Yerevan",
    languages: ["Armenian"],
    population: 2963234,
    flag: "https://flagcdn.com/am.svg",
    region: "Asia",
    area: 29743,
  },
  {
    name: "Aruba",
    capital: "Oranjestad",
    languages: ["Dutch", "(Eastern) Punjabi"],
    population: 106766,
    flag: "https://flagcdn.com/aw.svg",
    region: "Americas",
    area: 180,
  },
  {
    name: "Australia",
    capital: "Canberra",
    languages: ["English"],
    population: 25687041,
    flag: "https://flagcdn.com/au.svg",
    region: "Oceania",
    area: 7692024,
  },
  {
    name: "Austria",
    capital: "Vienna",
    languages: ["German"],
    population: 8917205,
    flag: "https://flagcdn.com/at.svg",
    region: "Europe",
    area: 83871,
  },
  {
    name: "Azerbaijan",
    capital: "Baku",
    languages: ["Azerbaijani"],
    population: 10110116,
    flag: "https://flagcdn.com/az.svg",
    region: "Asia",
    area: 86600,
  },
  {
    name: "Bahamas",
    capital: "Nassau",
    languages: ["English"],
    population: 393248,
    flag: "https://flagcdn.com/bs.svg",
    region: "Americas",
    area: 13943,
  },
  {
    name: "Bahrain",
    capital: "Manama",
    languages: ["Arabic"],
    population: 1701583,
    flag: "https://flagcdn.com/bh.svg",
    region: "Asia",
    area: 765,
  },
  {
    name: "Bangladesh",
    capital: "Dhaka",
    languages: ["Bengali"],
    population: 164689383,
    flag: "https://flagcdn.com/bd.svg",
    region: "Asia",
    area: 147570,
  },
  {
    name: "Barbados",
    capital: "Bridgetown",
    languages: ["English"],
    population: 287371,
    flag: "https://flagcdn.com/bb.svg",
    region: "Americas",
    area: 430,
  },
  {
    name: "Belarus",
    capital: "Minsk",
    languages: ["Belarusian", "Russian"],
    population: 9398861,
    flag: "https://flagcdn.com/by.svg",
    region: "Europe",
    area: 207600,
  },
  {
    name: "Belgium",
    capital: "Brussels",
    languages: ["Dutch", "French", "German"],
    population: 11555997,
    flag: "https://flagcdn.com/be.svg",
    region: "Europe",
    area: 30528,
  },
  {
    name: "Belize",
    capital: "Belmopan",
    languages: ["English", "Spanish"],
    population: 397621,
    flag: "https://flagcdn.com/bz.svg",
    region: "Americas",
    area: 22966,
  },
  {
    name: "Benin",
    capital: "Porto-Novo",
    languages: ["French"],
    population: 12123198,
    flag: "https://flagcdn.com/bj.svg",
    region: "Africa",
    area: 112622,
  },
  {
    name: "Bermuda",
    capital: "Hamilton",
    languages: ["English"],
    population: 63903,
    flag: "https://flagcdn.com/bm.svg",
    region: "Americas",
    area: 54,
  },
  {
    name: "Bhutan",
    capital: "Thimphu",
    languages: ["Dzongkha"],
    population: 771612,
    flag: "https://flagcdn.com/bt.svg",
    region: "Asia",
    area: 38394,
  },
  {
    name: "Bolivia (Plurinational State of)",
    capital: "Sucre",
    languages: ["Spanish", "Aymara", "Quechua"],
    population: 11673029,
    flag: "https://flagcdn.com/bo.svg",
    region: "Americas",
    area: 1098581,
  },
  {
    name: "Bonaire, Sint Eustatius and Saba",
    capital: "Kralendijk",
    languages: ["Dutch"],
    population: 17408,
    flag: "https://flagcdn.com/bq.svg",
    region: "Americas",
    area: 294,
  },
  {
    name: "Bosnia and Herzegovina",
    capital: "Sarajevo",
    languages: ["Bosnian", "Croatian", "Serbian"],
    population: 3280815,
    flag: "https://flagcdn.com/ba.svg",
    region: "Europe",
    area: 51209,
  },
  {
    name: "Botswana",
    capital: "Gaborone",
    languages: ["English", "Tswana"],
    population: 2351625,
    flag: "https://flagcdn.com/bw.svg",
    region: "Africa",
    area: 582000,
  },
  {
    name: "Bouvet Island",
    languages: ["Norwegian", "Norwegian Bokmål", "Norwegian Nynorsk"],
    population: 0,
    flag: "https://flagcdn.com/bv.svg",
    region: "Antarctic Ocean",
    area: 49,
  },
  {
    name: "Brazil",
    capital: "Brasília",
    languages: ["Portuguese"],
    population: 212559409,
    flag: "https://flagcdn.com/br.svg",
    region: "Americas",
    area: 8515767,
  },
  {
    name: "British Indian Ocean Territory",
    capital: "Diego Garcia",
    languages: ["English"],
    population: 3000,
    flag: "https://flagcdn.com/io.svg",
    region: "Africa",
    area: 60,
  },
  {
    name: "United States Minor Outlying Islands",
    languages: ["English"],
    population: 300,
    flag: "https://flagcdn.com/um.svg",
    region: "Americas",
  },
  {
    name: "Virgin Islands (British)",
    capital: "Road Town",
    languages: ["English"],
    population: 30237,
    flag: "https://flagcdn.com/vg.svg",
    region: "Americas",
    area: 151,
  },
  {
    name: "Virgin Islands (U.S.)",
    capital: "Charlotte Amalie",
    languages: ["English"],
    population: 106290,
    flag: "https://flagcdn.com/vi.svg",
    region: "Americas",
    area: 346.36,
  },
];

// Global Variables
const numFormatter = Intl.NumberFormat("en-US");
const countriesContainer = document.querySelector(".countries-container");
const categoryHeadingContainer = document.querySelector(
  ".category-heading-container"
);
const worldPopulation = countries_data.reduce(
  (acc, cur) => cur.population + acc,
  0
);
let currentState;
let dataGenerated = false;
//
//
//
//
//
//Init func
const init = function () {
  document.querySelector(".country-population").textContent =
    numFormatter.format(worldPopulation);

  document.querySelector(
    "h2"
  ).textContent = `Currently we have ${countries_data.length} Countries`;
};
init();

// Event delegation
categoryHeadingContainer.addEventListener("click", function (e) {
  e.preventDefault();
  const target = e.target.classList.contains("category-heading");
  if (!target) return;
  fetchData(e.target.dataset.type);
});

const fetchData = function (state = "population") {
  if (dataGenerated && state === currentState) return;
  else {
    dataGenerated = true;
    currentState = state;
    const [first, ...rest] = document.querySelectorAll(".country-container");
    rest.forEach((el) => el.remove(el));
    state === "population" ? loadPopulation() : loadLanguages();
  }
};

const loadPopulation = function () {
  const topCountriesPopulation = countries_data
    .sort((a, b) => b.population - a.population)
    .filter((_, i) => i < 10);
  return loadHTML(topCountriesPopulation);
};

const loadLanguages = function () {
  const languages = [
    ...new Set(countries_data.flatMap((el) => el.languages)),
  ].map((language) => {
    // const object = { language, times: 0 };
    // return object;
    return { language, times: 0 };
  });

  const countLanguages = countries_data.flatMap((el) => el.languages);
  countLanguages.forEach((lang) => {
    const found = languages.find((el) => lang === el.language);
    found.times++;
  });

  const sortedLanguages = languages
    .sort((a, b) => b.times - a.times)
    .filter((_, i) => i < 10);

  return loadHTML(sortedLanguages);
};

const loadHTML = function (arr) {
  document.querySelector(".category-title").textContent =
    currentState === "population"
      ? "10 Most populated countries in the world"
      : "10 Most spoken languages in the world";
  arr.forEach((el) => {
    //Inserting the HTML
    countriesContainer.insertAdjacentHTML(
      "beforeend",
      `        <div class="country-container">
   <p class="country-name">${
     currentState === "population" ? el.name : el.language
   }</p>
      <p class="country-graph"><span class="graph" style="width:${
        currentState === "population"
          ? (el.population / worldPopulation) * 100
          : (el.times / countries_data.flatMap((el) => el.languages).length) *
            100
      }%">&nbsp;</span></p>
          <p class="country-population">${
            currentState === "population"
              ? numFormatter.format(el.population)
              : numFormatter.format(el.times)
          }
          </p>
</div>
`
    );
  });
};
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0%;
  padding: 0%;
}

body {
  font-size: 62.5%;
  font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande",
    "Lucida Sans", Arial, sans-serif;
  background-color: whitesmoke;
}

header {
  height: 20vh;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 1rem;

  font-size: 2rem;
}

h1 {
  text-decoration: underline;
}
h2 {
  font-size: 1.8rem;
}

.category-container {
  background-color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  font-size: 1.5rem;

  box-shadow: 0.5rem 0.2rem 1rem rgba(0, 0, 0, 0.2),
    0.5rem -0.2rem 1rem rgba(0, 0, 0, 0.2);

  padding: 1rem;
}
.category-heading-container {
  display: flex;
  align-items: center;
  gap: 2rem;
  margin-bottom: 1rem;
}
.category-heading {
  padding: 1rem;
  background: orange;
  border-radius: 1rem;
  color: white;
  font-weight: bold;
  letter-spacing: 2px;

  box-shadow: 0rem 0rem 0.2rem rgba(0, 0, 0, 0.4);

  transition: background-color 0.3s, color 0.2s, box-shadow 0.3s;
}
.category-title {
}

/* Country */
.countries-container {
  height: 60vh;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-direction: column;

  font-size: 1.5rem;
  padding-bottom: 2rem;
  overflow: auto;
}

.countries-container > *:first-child {
  margin-top: 2rem;
}

.country-container {
  padding: 1rem;
  width: 50%;
  display: grid;
  grid-template-columns: minmax(10rem, 10fr) 80fr minmax(10rem, 10fr);
  align-items: center;
  justify-content: center;
  gap: 2rem;
}

.country-name {
  display: flex;
  align-items: center;
  justify-content: left;
}

.country-graph {
  width: 100%;
}
.graph {
  display: inline-block;
  width: 100%;
  background-color: orange;
}
.country-population {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-start;
}

/* HOVER STATES */
.category-heading:hover {
  background-color: rgba(255, 166, 0, 0.119);
  color: orange;
  box-shadow: 0rem 0rem 0.2rem rgba(0, 0, 0, 0.2);
  cursor: pointer;
}
<!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" />
    <link rel="stylesheet" href="style.css" />
    <title>Country Visualization</title>
  </head>
  <body>
    <header>
      <h1>World Countries Data</h1>
      <h2>&nbsp;</h2>
    </header>
    <main>
      <div class="category-container">
        <div class="category-heading-container">
          <p class="category-heading" data-type="population">Population</p>
          <p class="category-heading" data-type="languages">Languages</p>
        </div>
        <p class="category-title">&nbsp;</p>
      </div>
      <div class="countries-container">
        <div class="country-container">
          <p class="country-name">World</p>
          <p class="country-graph"><span class="graph">&nbsp;</span></p>
          <p class="country-population">&nbsp;</p>
        </div>
      </div>
    </main>
  </body>
  <script type="module" src="script.js"></script>
</html>

\$\endgroup\$
4
  • \$\begingroup\$ This site requires that code be posted here. The code at a codepen link can change, making the answers we give non-sensical. \$\endgroup\$
    – Teepeemm
    Aug 1, 2022 at 15:13
  • \$\begingroup\$ @Teepeemm it's too much code for it to be written here. \$\endgroup\$
    – noharm
    Aug 1, 2022 at 20:04
  • 1
    \$\begingroup\$ It should fit if you cut countries_data down to just 20 or 30 countries. The results might become different, but that won't really change the review of your code. \$\endgroup\$
    – Teepeemm
    Aug 1, 2022 at 20:08
  • \$\begingroup\$ @Teepeemm u r correct, will do \$\endgroup\$
    – noharm
    Aug 1, 2022 at 20:37

1 Answer 1

1
\$\begingroup\$

Your function loadHTML uses countriesContainer.insertAdjacentHTML and then creates a whole HTML chunk as a string. I would consider this bad practice because your IDE will not pick up on syntax errors in your code (for example forgetting a closing tag). You also won't get code completion/intellisense for the HTML you use as a string. You can use createElement to programmatically create HTML:

A simplified example of creating HTML by code:

   let div = document.createElement("div")
   div.classList.add("country-container")
   div.innerText = el.name
   countriesContainer.appendChild(div)

Another tip: for readability's sake I would split up the functions for languages and population, so that you don't need so many if statements and ternary expressions everywhere.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.