LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-21-2020, 07:31 AM   #1
GPGAgent
Senior Member
 
Registered: Oct 2018
Location: Surrey UK
Distribution: Mint 20 xfce 64bit
Posts: 1,026
Blog Entries: 3

Rep: Reputation: 133Reputation: 133
Question Javascript Sort Table Columns


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
Attached Thumbnails
Click image for larger version

Name:	Unsorted.png
Views:	56
Size:	15.0 KB
ID:	33040   Click image for larger version

Name:	Ascending.png
Views:	54
Size:	15.2 KB
ID:	33041   Click image for larger version

Name:	Descending.png
Views:	52
Size:	15.1 KB
ID:	33042  

Last edited by GPGAgent; 04-21-2020 at 07:42 AM.
 
Old 04-21-2020, 08:04 AM   #2
SoftSprocket
Member
 
Registered: Nov 2014
Posts: 399

Rep: Reputation: Disabled
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
 
1 members found this post helpful.
Old 04-21-2020, 08:25 AM   #3
GPGAgent
Senior Member
 
Registered: Oct 2018
Location: Surrey UK
Distribution: Mint 20 xfce 64bit
Posts: 1,026

Original Poster
Blog Entries: 3

Rep: Reputation: 133Reputation: 133
Quote:
Originally Posted by SoftSprocket View Post
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?

Last edited by GPGAgent; 04-21-2020 at 09:04 AM.
 
Old 04-22-2020, 07:49 AM   #4
SoftSprocket
Member
 
Registered: Nov 2014
Posts: 399

Rep: Reputation: Disabled
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>
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Why does open office table only show 16 of 21 columns in table format columns? 1sweetwater! Linux - Software 1 12-03-2014 01:19 PM
[SOLVED] bash suggestions to convert horizontal columns to vertical columns Guyverix Programming 14 01-24-2013 11:03 AM
SQL statements howto -- 3 columns input but 2 columns output fhleung Programming 3 11-29-2012 10:45 AM
Map 1 CSV's columns to matching columns in another CSV 2legit2quit Programming 7 10-27-2011 08:53 AM
[SOLVED] AWK: add columns while keep format for other columns cristalp Programming 3 10-13-2011 06:14 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:00 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration