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
}%"> </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> </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"> </p>
</div>
<div class="countries-container">
<div class="country-container">
<p class="country-name">World</p>
<p class="country-graph"><span class="graph"> </span></p>
<p class="country-population"> </p>
</div>
</div>
</main>
</body>
<script type="module" src="script.js"></script>
</html>
1 Answer 1
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.
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\$