Я создал список списка, содержащий некоторые данные о странах (сгруппированных по субрегионам, каждая страна содержит следующие данные: название, столица, население и площадь). Теперь я хотел бы добавить возможность скрывать или показывать все страны, входящие в его субрегион. Например, после нажатия на субрегион Северная Америка должны появиться все страны, принадлежащие NA, или скрыться, если они уже были показаны. Прямо сейчас все, что я могу сделать, это показать весь список субрегионов со всеми его странами, и я понятия не имею, как добавить возможность раскрывающегося списка. Буду крайне признателен за помощь.
Ниже приведен исходный код того, что я смог сделать.
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>Во-вторых, но не так важно, как во-первых, мне также нужно было бы добавить функцию сортировки и фильтрации каждого столбца после нажатия элемента div в самом верху. Так, например, после нажатия AREA в разделе заголовка страны должны быть отсортированы по их области. И опция фильтра, позволяющая показывать только страны, которые, например, начинаются с буквы «А».



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы можете сначала сгруппировать субрегионы, например,
const subRegions = data.reduce((r, a) => {
r[a.subregion] = r[a.subregion] || [];
r[a.subregion].push(a);
return r;
}, {});
А затем создайте элемент выбора и введите текст и значение соответственно.
Затем обработайте onchange и получите данные выбранного субрегиона, а не все сразу, как subRegions[subRegionName] .
Разветвленный пример:
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>Обновлять:
Вот обновленная версия, в которой каждый субрегион сгруппирован в виде аккордеона, и при переключении отображаются соответствующие страны в субрегионе.
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>@ fantomx775, смотрите обновленный ответ вместе с примером.
это выглядит действительно хорошо, спасибо. Можно ли добавить возможность сортировки и фильтрации? Например, щелчок по области в разделе заголовка отсортирует страны по области, а затем щелчок по имени отсортирует их по областям и именам, потому что были нажаты обе страны. Я имею в виду одновременное использование разных параметров сортировки и фильтрации. Параметр фильтрации может позволить отображать только страны, соответствующие выражению в фильтре, поэтому, например, при вводе «Eth» в фильтре имен должна отображаться только Эфиопия в Восточной Африке, а при вводе «Par» в столицах должна отображаться Франция в Западной Европе.
@ fantomx775, это выходит за рамки вашего текущего вопроса. Если вам нужны дополнительные вещи, поднимите для этого новый вопрос. Удачного кодирования!
Хорошо, тогда я задам новый вопрос, спасибо
@ fantomx775, пожалуйста, примите ответ, если он решит вашу проблему в этом вопросе.
Я попытался добавить возможность сортировки и фильтрации в Ваш код выше, но не могу этого сделать. Данные не сортируются для меня, и кажется, что единственный раз, когда мне разрешено сортировать, это в начале скрипта, когда вызывается функция f. Ты поможешь мне с этим? Заранее спасибо.
@ fantomx775, не могли бы вы добавить более подробную информацию о том, где вы хотите добавить функцию сортировки?
Функциональность сортировки должна быть назначена каждому из 4 элементов в разделе заголовка (Имя, Столица, Население и Площадь). Я хочу сделать так, чтобы после однократного щелчка, например, по имени, данные сортировались (по возрастанию) по имени, а после повторного щелчка по имени данные должны быть отсортированы в обратном порядке к предыдущей сортировке (по убыванию) и т. д. . И я хотел бы сделать возможным сортировку по паре столбцов одновременно, поэтому, например, после нажатия «Область» и «Столица» данные должны быть отсортированы как по площади, так и по столице.
@ fantomx775, вы спрашиваете больше, и Stackoverflow не является бесплатной службой кодирования. Возможно, некоторые другие могут помочь вам в этой функциональности здесь, в SO. Удачного кодирования!
ОК, это действительно приятно и прекрасно работает. Но мне нужно, чтобы это вело себя так, как на картинке, связанной здесь:codehim.com/menu/… Чтобы вы могли открывать пару субрегионов одновременно. Конечно, имея разные субрегионы вместо профиля, сообщения, настроек и т. д.