#javascript #sorting #html-table
#javascript #сортировка #html-таблица
Вопрос:
Мне нужно отсортировать таблицу по имени. Для сортировки я использую функцию
function sortArray(index) {
let arr = [];
rows.forEach( elem => {
arr.push(elem.children[index].textContent);
})
let sort = arr.sort( (a, b) => {
if ( a > b) {
return 1;
}
if (a < b) {
return -1;
}
return 0;
});
console.log(sort);
return sort;
}
но я не знаю, как перерисовать таблицу. Таблицу я создаю из файла JSON динамически. Для того, чтобы начать сортировку, вам нужно нажать на название поля, после чего должна отобразиться уже отсортированная таблица.
const buildHeader = data =>
Object.keys(data)
.map(k => `<th>${k}</th>`)
.join("");
const buildRow = data =>
Object.keys(data)
.map(k => `<td>${data[k]}</td>`)
.join("");
let element = document.querySelector(".people");
function showPeople(people) {
let table = document.createElement("table");
table.classList.add("people__table");
let thead = document.createElement("thead");
thead.innerHTML = `<tr class="head">${buildHeader(people[0])}</tr>`;
table.appendChild(thead);
let tbody = document.createElement("tbody");
tbody.innerHTML = people
.map(p => `<tr class="person">${buildRow(p)}</tr>`)
.join("");
table.appendChild(tbody);
element.appendChild(table);
}
const customPeople = data =>
data.map((p, i) => {
return {
name: p.name,
sex: p.sex,
born: p.born,
died: p.died,
age: p.died - p.born,
mother: p.mother,
father: p.father,
};
});
showPeople(customPeople(ANCESTRY_FILE));
Комментарии:
1. Если вы для начала создаете таблицу динамически из JSON, нельзя ли повторить этот процесс с отсортированными данными?
2.в стороне: этот подход работает, но innerHTML на самом деле не нужен. HTMLTableElement оснащен такими методами создания таблиц, как
createTHead
insertRow
и т.д. Аналогично HtmlTableRow содержит такие методы, какinsertCell
,deleteCell
и т.д.3. @Lewis Это, конечно, возможно, но как сделать так, чтобы эти данные сортировались щелчками по названиям полей
Ответ №1:
Что-то вроде этой sortTable
функции выполнило бы эту работу:
function sortTable(tbody, index, ascending) {
Array.prototype.slice.call(tbody.children).sort(
(tr1, tr2) => tr1.children[index].textContent.localeCompare(tr2.children[index].textContent) * (ascending ? 1 : -1)
).forEach(tr => tbody.appendChild(tr));
}
// demonstration
(function(){
const thead_tr = document.getElementById('thdtr');
const tbody = document.getElementById('tbd');
function makeCell() {
const td = document.createElement('td');
td.appendChild(document.createTextNode(Math.round(Math.random() * 999999999).toString(36)));
return td;
}
function makeRow() {
const tr = document.createElement('tr');
for(let i = 0; i < thead_tr.children.length; i ) tr.appendChild(makeCell());
return tr;
}
// adds click-to-sort functionality
Array.prototype.forEach.call(thead_tr.children, (th, index) => {
let asc_toggle = false; // false will start off in ascending order
th.addEventListener('click', event => sortTable(tbody, index, asc_toggle = !asc_toggle));
});
// fills the table with random alphanumeric data
for(let i = 0; i < 100; i ) tbody.appendChild(makeRow());
}());
<table>
<thead>
<tr id="thdtr">
<th>col 1</th>
<th>col 2</th>
<th>col 3</th>
</tr>
</thead>
<tbody id="tbd">
</tbody>
<table>
Моя sortTable
функция — это универсальная функция сортировки таблиц на месте, которая должна работать с любой таблицей. Он принимает 3 параметра:
tbody
—DOMElement
— Ссылка либо наtbody
элемент, либо на самtable
элемент, в зависимости от того, что содержитtr
элементы (строки).index
—Number
— Индекс столбца для сортировки по (начинается с0
).ascending
—Boolean
— Является ли порядок возрастающим (true
) или убывающим (false
)
Пример использования для использования с вашим текущим кодом:
sortTable(document.querySelector('.people__table tbody'), 0, true);
Ответ №2:
Вы могли бы повторно отправить строки в тело таблиц:
const body = document querySelector(".people__table > tbody");
for(const el of sort)
body.appendChild(el);
Или вы просто сортируете данные и повторно создаете всю таблицу.
Комментарии:
1. Это, конечно, возможно, но как сделать так, чтобы эти данные сортировались щелчками по названиям полей. Используя способ сортировки, запустили файл JSON.
Ответ №3:
Пожалуйста, найдите пример ниже:
let data = generateData();
let columns = [
{
name: "id",
callback: function() {
flags.id *= -1;
doSortInt("id", flags.id);
}
},
{
name: "name",
callback: function() {
flags.name *= -1;
doSortStrings("name", flags.name);
}
},
{
name: "age",
callback: function() {
flags.age *= -1;
doSortInt("age", flags.age);
}
}
];
var flags = {
id: -1,
name: -1,
age: -1
};
createBasicTable(columns);
populateDataToTable(data);
function doSortInt(prop, flag) {
data.sort(function(a, b) {
return flag * (b[prop] - a[prop]);
});
populateDataToTable(data);
}
function doSortStrings(prop, flag) {
data.sort(function(a, b) {
return flag * ("" a[prop]).localeCompare(b[prop]);
});
populateDataToTable(data);
}
/**
* This function is used to fill in the table with data from array
*/
function populateDataToTable(data) {
let tableBody = document.querySelector("#table-body");
// remove all childs
while (tableBody.firstChild) {
tableBody.removeChild(tableBody.firstChild);
}
// add new data
data.forEach(function(el) {
let tr = document.createElement("tr");
let th1 = document.createElement("th");
th1.innerHTML = el.id;
tr.appendChild(th1);
let th2 = document.createElement("th");
th2.innerHTML = el.name;
tr.appendChild(th2);
let th3 = document.createElement("th");
th3.innerHTML = el.age;
tr.appendChild(th3);
tableBody.appendChild(tr);
});
}
/**
* This function is used to create a basic empty table
*/
function createBasicTable(columns) {
let element = document.querySelector("#table-container");
let table = document.createElement("table");
table.classList.add("people__table");
let thead = document.createElement("thead");
let tr = document.createElement("tr");
columns.forEach(function(col) {
let th = document.createElement("th");
th.classList.add("head");
th.innerHTML = col.name;
th.addEventListener("click", col.callback);
// add listener here
tr.appendChild(th);
});
thead.appendChild(tr);
table.appendChild(thead);
let tbody = document.createElement("tbody");
tbody.id = "table-body";
table.appendChild(tbody);
element.appendChild(table);
}
/**
* This function is used to generate some data for the table
*/
function generateData() {
let data = [];
for (var i = 0; i < 100; i ) {
let obj = {
id: i,
name: "Name_" (i 1),
age: 30 i * 2
};
data.push(obj);
}
return data;
}
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div id="table-container"></div>
</body>
</html>
Основными моментами являются:
В массиве определений столбцов у вас есть обратные вызовы для каждого заголовка столбца. Затем вы вызываете функцию
createBasicTable
который создает пустую таблицу без данных. И в этой функции вы регистрируете обратные вызовы заголовков столбцов. Тогда у вас есть функция
populateDataToTable
который принимает массив в качестве параметра и использует этот массив для построения строк таблицы.
Наконец, в ваших обратных вызовах вам просто нужно правильно отсортировать массив данных и обновить содержимое таблицы с помощью функции:
populateDataToTable
p.s. Код не является совершенным, но он должен по крайней мере дать вам подсказку, как реализовать эту функциональность.
Я постараюсь улучшить код завтра.
Комментарии:
1. Если вы посмотрите на мой ответ, вы должны быть в состоянии увидеть, что решение этой проблемы совсем не очень сложное и не требует полного пересмотра алгоритма, используемого для генерации таблицы.