LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Javascript Sort Table Columns (https://www.linuxquestions.org/questions/programming-9/javascript-sort-table-columns-4175673645/)

GPGAgent 04-21-2020 07:31 AM

Javascript Sort Table Columns
 
3 Attachment(s)
On our Intranet at work I look after a web app that uses a simple html table to display results - nothing complicated, data is retrieved from a SQL database with a simple select statement.
I want to add sorting capability to the table and I have a nice simple Javascript that does it nicely all bar one point - I would like to add an arrow to indicate the sort order.

I also have a complicated Javascript that does add a direction of sort indicator, so i thought I could just lift that bit of code and add into the simple Javascript, but it's beyond me - maybe someone can help - much appreciated.

Here's the simple javascript and html thatworks nicely:
Code:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
   
  <script>
  function sortTable(table, col, reverse) {
    var tb = table.tBodies[0], // use `<tbody>` to ignore `<thead>` and `<tfoot>` rows
        tr = Array.prototype.slice.call(tb.rows, 0), // put rows into array
        i;
    reverse = -((+reverse) || -1);
    tr = tr.sort(function (a, b) { // sort rows
        return reverse // `-1 *` if want opposite order
            * (a.cells[col].textContent.trim() // using `.textContent.trim()` for test
                .localeCompare(b.cells[col].textContent.trim())
              );
    });
    for(i = 0; i < tr.length; ++i) tb.appendChild(tr[i]); // append each row in order
}

function makeSortable(table) {
    var th = table.tHead, i;
    th && (th = th.rows[0]) && (th = th.cells);
    if (th) i = th.length;
    else return; // if no `<thead>` then do nothing
    while (--i >= 0) (function (i) {
        var dir = 1;
        th[i].addEventListener('click', function () {sortTable(table, i, (dir = 1 - dir))});
    }(i));
}

function makeAllSortable(parent) {
    parent = parent || document.body;
    var t = parent.getElementsByTagName('table'), i = t.length;
    while (--i >= 0) makeSortable(t[i]);
}

    window.onload = function () {makeAllSortable();};
  </script> 

  </head>
<body>

  <H1>Test Sorting table</h1>
  <table border=1 cellspacing=0>
  <thead>
    <tr>
      <th>Asset No</th>
      <th>Description</th>
      <th>Location</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>JKEL03001234</td><td>Emergency Light</td><td>Rm 35</td>
    </tr>
    <tr>
      <td>JKEL03001239</td><td>Emergency Light</td><td>Rm 36</td>
    </tr>
    <tr>
      <td>JKEP01001234</td><td>Emergency Power Off</td><td>Rm 37</td>
    </tr>
    <tr>
      <td>JKED03001234</td><td>Emergency Door</td><td>Rm 38</td>
    </tr>
  </tbody>
</table>
</body>
</html>

And here's a clip of the code from the more complicated Javascript, I think it's the bit that adds an up/down triangle:
Code:

    sheet.insertRule('table.js-sort-asc thead tr > .js-sort-active:not(.js-sort-none):after {content: "\\25b2";font-size: 0.7em;padding-left: 3px;line-height: 0.7em;}', 0);
    sheet.insertRule('table.js-sort-desc thead tr > .js-sort-active:not(.js-sort-none):after {content: "\\25bc";font-size: 0.7em;padding-left: 3px;line-height: 0.7em;}', 0);

Maybe that doesn't help without the complete script, but it's far too long.

I've also attached three screenshots of the desired effect I'm after.

Thanks guys and gals - hope someone can help

SoftSprocket 04-21-2020 08:04 AM

I guess it would be redundant to suggest the clip you added inserts a rule into a style sheet. The unicode in the content field is for up arrow (25b2) and down arrow (25bc) , however there isn't a style sheet included in the code you posted and the rule will need application the element you wish to apply it to.

This link might help with your next step: https://developer.mozilla.org/en-US/...eet/insertRule

GPGAgent 04-21-2020 08:25 AM

Quote:

Originally Posted by SoftSprocket (Post 6114111)
I guess it would be redundant to suggest the clip you added inserts a rule into a style sheet. The unicode in the content field is for up arrow (25b2) and down arrow (25bc) , however there isn't a style sheet included in the code you posted and the rule will need application the element you wish to apply it to.

This link might help with your next step: https://developer.mozilla.org/en-US/...eet/insertRule

Useful link, cheers, and here's the complete script that uses the up and down triangle:
Code:

<!DOCTYPE html>
<!--- https://jsbin.com/?html,output --->
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
   
  <script>
 function sortTable(Table, col, dir) {
    var sortClass, i;

    sortTable.sortCol = -1;
    sortClass = Table.className.match(/js-sort-\d+/);
    if (null != sortClass) {
        sortTable.sortCol = sortClass[0].replace(/js-sort-/, '');
        Table.className = Table.className.replace(new RegExp(' ?' + sortClass[0] + '\\b'), '');
    }
    if ('undefined' === typeof col) {
        col = sortTable.sortCol;
    }

    if ('undefined' !== typeof dir) {
        sortTable.sortDir = dir == -1 || dir == 'desc' ? -1 : 1;
    } else {
        sortClass = Table.className.match(/js-sort-(a|de)sc/);
        if (null != sortClass && sortTable.sortCol == col) {
            sortTable.sortDir = 'js-sort-asc' == sortClass[0] ? -1 : 1;
        } else {
            sortTable.sortDir = 1;
        }
    }
    Table.className = Table.className.replace(/ ?js-sort-(a|de)sc/g, '');

    Table.className += ' js-sort-' + col;
    sortTable.sortCol = col;

    Table.className += ' js-sort-' + (sortTable.sortDir == -1 ? 'desc' : 'asc');

    if (col < Table.tHead.rows[Table.tHead.rows.length - 1].cells.length) {
        sortClass = Table.tHead.rows[Table.tHead.rows.length - 1].cells[col].className.match(/js-sort-[-\w]+/);
    }
    for (i = 0; i < Table.tHead.rows[Table.tHead.rows.length - 1].cells.length; i++) {
        if (col == Table.tHead.rows[Table.tHead.rows.length - 1].cells[i].getAttribute('data-js-sort-colNum')) {
            sortClass = Table.tHead.rows[Table.tHead.rows.length - 1].cells[i].className.match(/js-sort-[-\w]+/);
        }
    }
    if (null != sortClass) {
        sortTable.sortFunc = sortClass[0].replace(/js-sort-/, '');
    } else {
        sortTable.sortFunc = 'string';
    }
    Table.querySelectorAll('.js-sort-active').forEach(function(Node) {
        Node.className = Node.className.replace(/ ?js-sort-active\b/, '');
    });
    Table.querySelectorAll('[data-js-sort-colNum="' + col + '"]:not(:empty)').forEach(function(Node) {
        Node.className += ' js-sort-active';
    });

    var rows = [],
        TBody = Table.tBodies[0];

    for (i = 0; i < TBody.rows.length; i++) {
        rows[i] = TBody.rows[i];
    }
    if ('none' != sortTable.sortFunc) {
        rows.sort(sortTable.compareRow);
    }

    while (TBody.firstChild) {
        TBody.removeChild(TBody.firstChild);
    }
    for (i = 0; i < rows.length; i++) {
        TBody.appendChild(rows[i]);
    }
}

sortTable.compareRow = function(RowA, RowB) {
    var valA, valB;
    if ('function' != typeof sortTable[sortTable.sortFunc]) {
        sortTable.sortFunc = 'string';
    }
    valA = sortTable[sortTable.sortFunc](RowA.cells[sortTable.sortCol]);
    valB = sortTable[sortTable.sortFunc](RowB.cells[sortTable.sortCol]);

    return valA == valB ? 0 : sortTable.sortDir * (valA > valB ? 1 : -1);
};

sortTable.stripTags = function(html) {
    return html.replace(/<\/?[a-z][a-z0-9]*\b[^>]*>/gi, '');
};

sortTable.date = function(Cell) {
    // If okDate library is available, Use it for advanced Date processing
    if (okDate) {
        var Date = okDate(sortTable.stripTags(Cell.innerHTML));
        return Date ? Date.getTime() : 0;
    } else {
        return (new Date(sortTable.stripTags(Cell.innerHTML))).getTime() || 0;
    }
};

sortTable.number = function(Cell) {
    return Number(sortTable.stripTags(Cell.innerHTML).replace(/[^-\d.]/g, ''));
};

sortTable.string = function(Cell) {
    return sortTable.stripTags(Cell.innerHTML).toLowerCase();
};

sortTable.raw = function(Cell) {
    return Cell.innerHTML;
};

sortTable.last = function(Cell) {
    return sortTable.stripTags(Cell.innerHTML).split(' ').pop().toLowerCase();
};

sortTable.input = function(Cell) {
    for (var i = 0; i < Cell.children.length; i++) {
        if ('object' == typeof Cell.children[i]
            && 'undefined' != typeof Cell.children[i].value
        ) {
            return Cell.children[i].value.toLowerCase();
        }
    }

    return sortTable.string(Cell);
};

sortTable.none = function(Cell) {
    return null;
};

sortTable.getClickHandler = function(Table, col) {
    return function() {
        sortTable(Table, col);
    };
};

sortTable.init = function() {
    var THead, Tables, Handler;
    if (document.querySelectorAll) {
        Tables = document.querySelectorAll('table.js-sort-table');
    } else {
        Tables = document.getElementsByTagName('table');
    }

    for (var i = 0; i < Tables.length; i++) {
        if (!document.querySelectorAll && null === Tables[i].className.match(/\bjs-sort-table\b/)) {
            continue;
        }

        if (Tables[i].attributes['data-js-sort-table']) {
            continue;
        }

        if (!Tables[i].tHead) {
            THead = document.createElement('thead');
            THead.appendChild(Tables[i].rows[0]);
            Tables[i].insertBefore(THead, Tables[i].children[0]);
        } else {
            THead = Tables[i].tHead;
        }

        for (var rowNum = 0; rowNum < THead.rows.length; rowNum++) {
            for (var cellNum = 0, colNum = 0; cellNum < THead.rows[rowNum].cells.length; cellNum++) {
                THead.rows[rowNum].cells[cellNum].setAttribute('data-js-sort-colNum', colNum);
                Handler = sortTable.getClickHandler(Tables[i], colNum);
                window.addEventListener
                    ? THead.rows[rowNum].cells[cellNum].addEventListener('click', Handler)
                    : window.attachEvent && THead.rows[rowNum].cells[cellNum].attachEvent('onclick', Handler);
                colNum += THead.rows[rowNum].cells[cellNum].colSpan;
            }
        }

        Tables[i].setAttribute('data-js-sort-table', 'true')
    }

    var element = document.createElement('style');
    document.head.insertBefore(element, document.head.childNodes[0]);
    var sheet = element.sheet;
    sheet.insertRule('table.js-sort-asc thead tr > .js-sort-active:not(.js-sort-none):after {content: "\\25b2";font-size: 0.7em;padding-left: 3px;line-height: 0.7em;}', 0);
    sheet.insertRule('table.js-sort-desc thead tr > .js-sort-active:not(.js-sort-none):after {content: "\\25bc";font-size: 0.7em;padding-left: 3px;line-height: 0.7em;}', 0);
};

// Run sortTable.init() when the page loads
window.addEventListener
    ? window.addEventListener('load', sortTable.init, false)
    : window.attachEvent && window.attachEvent('onload', sortTable.init)
    ;

if (typeof NodeList.prototype.forEach !== "function") {
    NodeList.prototype.forEach = Array.prototype.forEach;
}
  </script> 

  </head>
<body>

  <H1>Test Sorting table</h1>
<!---  <table border=1 cellspacing=0> --->
<table class="js-sort-table" id="demo1" border=1 cellspacing=0>

  <thead>
    <tr>
      <th>Asset No</th>
      <th>Description</th>
      <th>Location</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>JKEL03001234</td><td>Emergency Light</td><td>Rm 35</td>
    </tr>
    <tr>
      <td>JKEL03001239</td><td>Emergency Light</td><td>Rm 36</td>
    </tr>
    <tr>
      <td>JKEP01001234</td><td>Emergency Power Off</td><td>Rm 37</td>
    </tr>
    <tr>
      <td>JKED03001234</td><td>Emergency Door</td><td>Rm 38</td>
    </tr>
  </tbody>
</table>
</body>
</html>

I said it was long!!!!

It looks like it has a dynamic style, I'm sure it should be possible to 'lift' this code and drop itinto the simpler script?

SoftSprocket 04-22-2020 07:49 AM

I wouldn't call it long. It does what you want so the answer is to understand what you need to do to use it so if you're not a programmer you may have a challenge if you need to modify it. On the other hand if you just want to use it in some page you just need to understand the format it expects from the table.

It looks for a table with the class "js-sort-table" and when a column header is clicked it adds an arrow showing the sort directing. Click it again it changes direction. It handles number, string and date comparison. I added a date column as an example but you can completely rewrite the table and it will work;

Code:

<table class="js-sort-table"  id="demo1" border=1 cellspacing=0>

  <thead>
    <tr>
      <th>Asset No</th>
      <th>Description</th>
      <th>Location</th>
      <th>Date</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>JKEL03001234</td><td>Emergency Light</td><td>Rm 35</td><td>2020-04-09</td>
    </tr>
    <tr>
      <td>JKEL03001239</td><td>Emergency Light</td><td>Rm 36</td><td>2020-04-10</td>
    </tr>
    <tr>
      <td>JKEP01001234</td><td>Emergency Power Off</td><td>Rm 37</td><td>2020-04-11</td>
    </tr>
    <tr>
      <td>JKED03001234</td><td>Emergency Door</td><td>Rm 38</td><td>2020-04-12</td>
    </tr>
  </tbody>
</table>



All times are GMT -5. The time now is 12:52 PM.