Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Sorting Nulls Wrong In HTML Table

I'm using the below JavaScript code to sort my tables alphabetically and numerical. However, it puts rows with null values at the top instead of the bottom.

In the below image, taken from this URL I am working on, when sorting the table from biggest to smallest in the Rank Change column, nulls are at the top instead of the bottom.

*In this table, Null values are the cells with the NEW tag or a dash. *The problem applies to all columns/rows

Shouldn't Nulls be classed as less than 1 and sorted as such? What am I doing wrong?

Any help is really appreciated.

enter image description here

const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent;

const comparer = (idx, asc) => (a, b) => ((v1, v2) => 
    v1 !=='' && v2 !=='' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
    )(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));

document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
    const table = th.closest('table');
    Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
        .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
        .forEach(tr => table.appendChild(tr) );
})));
like image 737
Electron Avatar asked Mar 16 '20 01:03

Electron


1 Answers

You could take a check for null values first and the check both values for finiteness, like numbers or strings who are coercible to number and then take either the delta of the numbers or sort by string.

Examples:

 v1   v2  (v1 === null) - (v2 === null) isFinite(v1) && isFinite(v2)             result
---- ---- ----------------------------- ---------------------------------------- ------
null null       true -  true ->  0       true -> v1 - v2                             0
null abc        true - false ->  1                                                   1
null  2         true - false ->  1                                                   1
abc  null      false -  true -> -1                                                  -1
 2   null      false -  true -> -1                                                  -1
abc  abc       false - false ->  0      false -> v1.toString().localeCompare(v2)     0
abc   2        false - false ->  0      false -> v1.toString().localeCompare(v2)     1
 2   abc       false - false ->  0      false -> v1.toString().localeCompare(v2)    -1
 2    2        false - false ->  0       true -> v1 - v2                             0

Code:

const comparer = (idx, asc) => (a, b) => ((v1, v2) =>
    (v1 === null) - (v2 === null) ||
    (isFinite(v1) && isFinite(v2)
        ? v1 - v2
        : v1.toString().localeCompare(v2)
    )
)(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));

Working Example:

var array = [null, 2, 1, 20, 11, 'b', 'aaa', 'a', null];

array.sort((v1, v2) => 
    (v1 === null) - (v2 === null) ||
    (isFinite(v1) && isFinite(v2)
        ? v1 - v2
        : v1.toString().localeCompare(v2)
    )
);

console.log(...array);
like image 160
Nina Scholz Avatar answered Nov 02 '22 23:11

Nina Scholz