Добавление дополнительной сортировки в скрипт на JavaScript
Я не знаю языка JS. Но в моём проекте на Django понадобился скрипт для сортировки таблиц на странице html.
Я воспользовался находящимся в общем доступе скриптом: github. И мне понадобилось сделать так, чтобы при сортировке по определённому столбцу, содержащему много одинаковых значений, дополнительно упорядочивались значения в соседнем столбце.
Я расписал алгоритм словами и попытался повторить его на JS в коде скрипта. Суть проста: из уже отсортированного множества строк через set берутся уникальные значения в искомом сортируемом столбце. Для каждого значения в set находятся все строки с ним. Каждый набор строк для определённого значения в set во временном множестве сортируется и добавляется в новое общее множество. Множество первично отсортированных строк приравнивается ко множеству с вторичной сортировкой.
Но код не работает. При попытке сортировки в странице все строки пропадают. Значит, во множество вторично отсортированных строк ничего не пишется, так понимаю.
Моё добавление к оригинальному коду содержит комментарии на русском, начиная со строки "var new_rows = [] // Объявляем пустое множество 1", и заканчивая "rows = new_rows". Остальной код, который не мой, полностью рабочий, достаточно сделать комментарием строку "rows = new_rows".
Подскажите, пожалуйста, в чём ошибка?
document.addEventListener('click', function (e) {
var down_class = ' dir-d '
var up_class = ' dir-u '
var regex_dir = / dir-(u|d) /
var regex_table = /\bsortable\b/
var element = e.target
function reClassify(element, dir) {
element.className = element.className.replace(regex_dir, '') + dir
}
function getValue(element) {
// If you aren't using data-sort and want to make it just the tiniest bit smaller/faster
// comment this line and uncomment the next one
// return element.getAttribute('data-sort') || element.innerText
return element.innerText
}
if (element.nodeName === 'TH') {
try {
var tr = element.parentNode
// var table = element.offsetParent; // Fails with positioned table elements
// this is the only way to make really, really sure. A few more bytes though... ??
var table = tr.parentNode.parentNode
if (regex_table.test(table.className)) {
var column_index
var nodes = tr.cells
// reset thead cells and get column index
for (var i = 0; i < nodes.length; i++) {
if (nodes[i] === element) {
column_index = i
} else {
reClassify(nodes[i], '')
}
}
var dir = down_class
// check if we're sorting up or down, and update the css accordingly
if (element.className.indexOf(down_class) !== -1) {
dir = up_class
}
reClassify(element, dir)
// extract all table rows, so the sorting can start.
var org_tbody = table.tBodies[0]
// get the array rows in an array, so we can sort them...
var rows = [].slice.call(org_tbody.rows, 0)
var reverse = dir === up_class
// sort them using custom built in array sort.
rows.sort(function (a, b) {
var x = getValue((reverse ? a : b).cells[column_index])
var y = getValue((reverse ? b : a).cells[column_index])
// var y = (reverse ? b : a).cells[column_index].innerText
// var x = (reverse ? a : b).cells[column_index].innerText
return isNaN(x - y) ? x.localeCompare(y) : x - y
})
var new_rows = [] // Объявляем пустое множество 1
var unic_val = new Set() // Объявляем пустой set
// Создаём set из уникальных значений в сортируемом столбце. Они уже упорядочены.
for (var i = 0; i < rows.length; i++) {
unic_val.add(rows[i][column_index])
}
// Для элементов в set:
// Объявляем пустое множество 2
// Для строк в исходной коллекции rows:
// если значение в ячейке с номером сортируемого столбца строки Y равно уникальному значению I:
// добавить строку во множество 2
for (var i = 0; i < unic_val.length; i++) {
var tmp_rows = []
for (var y = 0; y < rows.length; y++) {
if (rows[y][column_index] == unic_val[i]) {
tmp_rows.push(rows[y])
}
}
// Проверяем индекс колонки
// Check the index of column
if (column_index == 4) {
// Сортируем строки с одинаковым значением той же функцией, что и всю таблицу
// Sort rows with identical value in rows[y][column_index]
tmp_rows.sort(function (a, b) {
var x = getValue((reverse ? a : b).cells[5])
var y = getValue((reverse ? b : a).cells[5])
return isNaN(x - y) ? x.localeCompare(y) : x - y
})
} else {}
// Добавляем вторично отсортированные строки во множество 1
// Extend new_rows
Array.prototype.push.apply(new_rows, tmp_rows)
}
// Требуемое множество строк равно вторично отсортированному
rows = new_rows
// Make a clone without content
var clone_tbody = org_tbody.cloneNode()
// Build a sorted table body and replace the old one.
while (rows.length) {
clone_tbody.appendChild(rows.splice(0, 1)[0])
}
// And finally insert the end result
table.replaceChild(clone_tbody, org_tbody)
}
} catch (error) {
// console.log(error)
}
}
})
Ответы (1 шт):
При помощи column.log() и консоли в режиме разработчика браузера разобрался, где не передаются данные. Погуглил, как правильно, и исправил. Теперь код может выполнять вторичную сортировку по требуемым столбцам.
Для сравнения приведу НЕВЕРНЫЙ код моей дополнительной сортировки:
var new_rows = [] // Объявляем пустое множество 1
var unic_val = new Set() // Объявляем пустой set
// Создаём set из уникальных значений в сортируемом столбце. Они уже упорядочены.
for (var i = 0; i < rows.length; i++) {
unic_val.add(rows[i][column_index])
}
// Для элементов в set:
// Объявляем пустое множество 2
// Для строк в исходной коллекции rows:
// если значение в ячейке с номером сортируемого столбца строки Y равно уникальному значению I:
// добавить строку во множество 2
for (var i = 0; i < unic_val.length; i++) {
var tmp_rows = []
for (var y = 0; y < rows.length; y++) {
if (rows[y][column_index] == unic_val[i]) {
tmp_rows.push(rows[y])
}
}
// Проверяем индекс колонки
// Check the index of column
if (column_index == 4) {
// Сортируем строки с одинаковым значением той же функцией, что и всю таблицу
// Sort rows with identical value in rows[y][column_index]
tmp_rows.sort(function (a, b) {
var x = getValue((reverse ? a : b).cells[5])
var y = getValue((reverse ? b : a).cells[5])
return isNaN(x - y) ? x.localeCompare(y) : x - y
})
} else {}
// Добавляем вторично отсортированные строки во множество 1
// Extend new_rows
Array.prototype.push.apply(new_rows, tmp_rows)
}
// Требуемое множество строк равно вторично отсортированному
rows = new_rows
И ВЕРНЫЙ код моей дополнительной сортировки:
var new_rows = [] // Объявляем пустое множество 1
var unic_val = new Set() // Объявляем пустой set
// Создаём set из уникальных значений в сортируемом столбце. Они уже упорядочены.
for (var i = 0; i < rows.length; i++) {
unic_val.add(getValue(rows[i].cells[column_index]))
}
// Для элементов в set:
// Объявляем пустое множество 2
// Для строк в исходной коллекции rows:
// если значение в ячейке с номером сортируемого столбца строки Y равно уникальному значению I:
// добавить строку во множество 2
for (let item of unic_val) {
var tmp_rows = []
for (var el = 0; el < rows.length; el++) {
if (getValue(rows[el].cells[column_index]) == item) {
tmp_rows.push(rows[el])
}
}
// Проверяем индекс колонки. Введите свои номера вместо 4 и 5.
// Check the index of column. Insert your numbers instead of 4 and 5.
if (column_index == 4) {
// Сортируем той же функцией строки с одинаковым значением в rows[el].cells[column_index], что и всю таблицу
// Sort rows with identical value in rows[el].cells[column_index]
tmp_rows.sort(function (a, b) {
var x = getValue((reverse ? a : b).cells[5])
var y = getValue((reverse ? b : a).cells[5])
return isNaN(x - y) ? x.localeCompare(y) : x - y
})
} else {}
// Добавляем вторично отсортированные строки во множество 1
// Extend new_rows
Array.prototype.push.apply(new_rows, tmp_rows)
}
// Требуемое множество строк равно вторично отсортированному
rows = new_rows
Т.е. просто в JS собственные методы set, отличные от методов множеств, плюс значение из ячейки строки во множестве строк таблицы rows берётся через getValue(имя_множества_строк[номер_строки].cells[индекс_колонки])
Приведу полный код скрипта с возможностью вторичной сортировки выбранных столбцов, мало ли, кому пригодится:
document.addEventListener('click', function (e) {
var down_class = ' dir-d '
var up_class = ' dir-u '
var regex_dir = / dir-(u|d) /
var regex_table = /\bsortable\b/
var element = e.target
function reClassify(element, dir) {
element.className = element.className.replace(regex_dir, '') + dir
}
function getValue(element) {
// If you aren't using data-sort and want to make it just the tiniest bit smaller/faster
// comment this line and uncomment the next one
// return element.getAttribute('data-sort') || element.innerText
return element.innerText
}
if (element.nodeName === 'TH') {
try {
var tr = element.parentNode
// var table = element.offsetParent; // Fails with positioned table elements
// this is the only way to make really, really sure. A few more bytes though... ??
var table = tr.parentNode.parentNode
if (regex_table.test(table.className)) {
var column_index
var nodes = tr.cells
// reset thead cells and get column index
for (var i = 0; i < nodes.length; i++) {
if (nodes[i] === element) {
column_index = i
} else {
reClassify(nodes[i], '')
}
}
var dir = down_class
// check if we're sorting up or down, and update the css accordingly
if (element.className.indexOf(down_class) !== -1) {
dir = up_class
}
reClassify(element, dir)
// extract all table rows, so the sorting can start.
var org_tbody = table.tBodies[0]
// get the array rows in an array, so we can sort them...
var rows = [].slice.call(org_tbody.rows, 0)
var reverse = dir === up_class
// sort them using custom built in array sort.
rows.sort(function (a, b) {
var x = getValue((reverse ? a : b).cells[column_index])
var y = getValue((reverse ? b : a).cells[column_index])
// var y = (reverse ? b : a).cells[column_index].innerText
// var x = (reverse ? a : b).cells[column_index].innerText
return isNaN(x - y) ? x.localeCompare(y) : x - y
})
// My additional code (without sort functions): start
var new_rows = [] // Объявляем пустое множество 1
var unic_val = new Set() // Объявляем пустой set
// Создаём set из уникальных значений в сортируемом столбце. Они уже упорядочены.
for (var i = 0; i < rows.length; i++) {
unic_val.add(getValue(rows[i].cells[column_index]))
}
// Для элементов в set:
// Объявляем пустое множество 2
// Для строк в исходной коллекции rows:
// если значение в ячейке с номером сортируемого столбца строки Y равно уникальному значению I:
// добавить строку во множество 2
for (let item of unic_val) {
var tmp_rows = []
for (var el = 0; el < rows.length; el++) {
if (getValue(rows[el].cells[column_index]) == item) {
tmp_rows.push(rows[el])
}
}
// Проверяем индекс колонки. Введите свои номера вместо 4 и 5.
// Check the index of column. Insert your numbers instead of 4 and 5.
if (column_index == 4) {
// Сортируем той же функцией строки с одинаковым значением в rows[el].cells[column_index], что и всю таблицу
// Sort rows with identical value in rows[el].cells[column_index]
tmp_rows.sort(function (a, b) {
var x = getValue((reverse ? a : b).cells[5])
var y = getValue((reverse ? b : a).cells[5])
return isNaN(x - y) ? x.localeCompare(y) : x - y
})
} else {}
// Добавляем вторично отсортированные строки во множество 1
// Extend new_rows
Array.prototype.push.apply(new_rows, tmp_rows)
}
// Требуемое множество строк равно вторично отсортированному
rows = new_rows
// My additional code (without sort functions): finish
// Make a clone without content
var clone_tbody = org_tbody.cloneNode()
// Build a sorted table body and replace the old one.
while (rows.length) {
clone_tbody.appendChild(rows.splice(0, 1)[0])
}
// And finally insert the end result
table.replaceChild(clone_tbody, org_tbody)
}
} catch (error) {
// console.log(error)
}
}
})