34

So basically I am running a mysql query that fetches data from my database and displays it in an easy to read layout for my users.

Name-----Address----Sales Person

You get the gist. And now I want to let the user sort the html table by let's say sales person. How would I easily do that using a drop down menu?

<div class='menu'>
  <ul>
    <li><a href='#'><span>Sales Person</span></a>
      <ul>
        <li><a href='#'><span>Melissa</span></a></li>
        <li><a href='#'><span>Justin</span></a></li>
        <li><a href='#'><span>Judy</span></a></li>
        <li><a href='#'><span>Skipper</span></a></li>
        <li><a href='#'><span>Alex</span></a></li>
      </ul>
    </li>
  </ul>
</div>
Penny Liu
  • 11,885
  • 5
  • 66
  • 81
h3tr1ck
  • 709
  • 2
  • 7
  • 15
  • 4
    Two basic approaches : sort server-side in your database query or use a javascript data structure that you sort browser side. Both will require much more work that is visible here. – Denys Séguret May 21 '12 at 10:43
  • Possible duplicate? http://stackoverflow.com/questions/202252/jquery-table-header-sort – verisimilitude May 21 '12 at 10:47

6 Answers6

50

Check if you could go with any of the below mentioned JQuery plugins. Simply awesome and provide wide range of options to work through, and less pains to integrate. :)

https://github.com/paulopmx/Flexigrid - Flexgrid
http://datatables.net/index - Data tables.
https://github.com/tonytomov/jqGrid

If not, you need to have a link to those table headers that calls a server-side script to invoke the sort.

montrealist
  • 5,440
  • 10
  • 45
  • 60
verisimilitude
  • 4,867
  • 2
  • 28
  • 33
  • I'm not sure your truely understanding my question. I want to be able to sort the data that is displayed as html when the query is run. So can I use data tables to do that still? – h3tr1ck May 21 '12 at 11:00
  • 14
    DataTables was so very insanely easy to setup and great documentation and examples. – Josh Peak Jun 10 '15 at 23:25
36

Here is another library.

Changes required are -

  1. Add sorttable js

  2. Add class name sortable to table.

Click the table headers to sort the table accordingly:

<script src="https://www.kryogenix.org/code/browser/sorttable/sorttable.js"></script>

<table class="sortable">
  <tr>
    <th>Name</th>
    <th>Address</th>
    <th>Sales Person</th>
  </tr>

  <tr class="item">
    <td>user:0001</td>
    <td>UK</td>
    <td>Melissa</td>
  </tr>
  <tr class="item">
    <td>user:0002</td>
    <td>France</td>
    <td>Justin</td>
  </tr>
  <tr class="item">
    <td>user:0003</td>
    <td>San Francisco</td>
    <td>Judy</td>
  </tr>
  <tr class="item">
    <td>user:0004</td>
    <td>Canada</td>
    <td>Skipper</td>
  </tr>
  <tr class="item">
    <td>user:0005</td>
    <td>Christchurch</td>
    <td>Alex</td>
  </tr>

</table>
smilyface
  • 4,259
  • 7
  • 40
  • 49
16

The way I have sorted HTML tables in the browser uses plain, unadorned Javascript.

The basic process is:

  1. add a click handler to each table header
  2. the click handler notes the index of the column to be sorted
  3. the table is converted to an array of arrays (rows and cells)
  4. that array is sorted using javascript sort function
  5. the data from the sorted array is inserted back into the HTML table

The table should, of course, be nice HTML. Something like this...

<table>
 <thead>
  <tr><th>Name</th><th>Age</th></tr>
 </thead>
 <tbody>
  <tr><td>Sioned</td><td>62</td></tr>
  <tr><td>Dylan</td><td>37</td></tr>
  ...etc...
 </tbody>
</table>

So, first adding the click handlers...

const table = document.querySelector('table'); //get the table to be sorted

table.querySelectorAll('th') // get all the table header elements
  .forEach((element, columnNo)=>{ // add a click handler for each 
    element.addEventListener('click', event => {
        sortTable(table, columnNo); //call a function which sorts the table by a given column number
    })
  })

This won't work right now because the sortTable function which is called in the event handler doesn't exist.

Lets write it...

function sortTable(table, sortColumn){
  // get the data from the table cells
  const tableBody = table.querySelector('tbody')
  const tableData = table2data(tableBody);
  // sort the extracted data
  tableData.sort((a, b)=>{
    if(a[sortColumn] > b[sortColumn]){
      return 1;
    }
    return -1;
  })
  // put the sorted data back into the table
  data2table(tableBody, tableData);
}

So now we get to the meat of the problem, we need to make the functions table2data to get data out of the table, and data2table to put it back in once sorted.

Here they are ...

// this function gets data from the rows and cells 
// within an html tbody element
function table2data(tableBody){
  const tableData = []; // create the array that'll hold the data rows
  tableBody.querySelectorAll('tr')
    .forEach(row=>{  // for each table row...
      const rowData = [];  // make an array for that row
      row.querySelectorAll('td')  // for each cell in that row
        .forEach(cell=>{
          rowData.push(cell.innerText);  // add it to the row data
        })
      tableData.push(rowData);  // add the full row to the table data 
    });
  return tableData;
}

// this function puts data into an html tbody element
function data2table(tableBody, tableData){
  tableBody.querySelectorAll('tr') // for each table row...
    .forEach((row, i)=>{  
      const rowData = tableData[i]; // get the array for the row data
      row.querySelectorAll('td')  // for each table cell ...
        .forEach((cell, j)=>{
          cell.innerText = rowData[j]; // put the appropriate array element into the cell
        })
    });
}

And that should do it.

A couple of things that you may wish to add (or reasons why you may wish to use an off the shelf solution): An option to change the direction and type of sort i.e. you may wish to sort some columns numerically ("10" > "2" is false because they're strings, probably not what you want). The ability to mark a column as sorted. Some kind of data validation.

Morteza24
  • 3
  • 4
Tom P
  • 5,479
  • 1
  • 19
  • 22
12

Another approach to sort HTML table. (based on W3.JS HTML Sort)

let tid = "#usersTable";
let headers = document.querySelectorAll(tid + " th");

// Sort the table element when clicking on the table headers
headers.forEach(function(element, i) {
  element.addEventListener("click", function() {
    w3.sortHTML(tid, ".item", "td:nth-child(" + (i + 1) + ")");
  });
});
th {
  cursor: pointer;
  background-color: coral;
}
<script src="https://www.w3schools.com/lib/w3.js"></script>
<link href="https://www.w3schools.com/w3css/4/w3.css" rel="stylesheet" />
<p>Click the <strong>table headers</strong> to sort the table accordingly:</p>

<table id="usersTable" class="w3-table-all">
  <!--     
  <tr>
    <th onclick="w3.sortHTML('#usersTable', '.item', 'td:nth-child(1)')">Name</th>
    <th onclick="w3.sortHTML('#usersTable', '.item', 'td:nth-child(2)')">Address</th>
    <th onclick="w3.sortHTML('#usersTable', '.item', 'td:nth-child(3)')">Sales Person</th>
  </tr> 
  -->
  <tr>
    <th>Name</th>
    <th>Address</th>
    <th>Sales Person</th>
  </tr>

  <tr class="item">
    <td>user:2911002</td>
    <td>UK</td>
    <td>Melissa</td>
  </tr>
  <tr class="item">
    <td>user:2201002</td>
    <td>France</td>
    <td>Justin</td>
  </tr>
  <tr class="item">
    <td>user:2901092</td>
    <td>San Francisco</td>
    <td>Judy</td>
  </tr>
  <tr class="item">
    <td>user:2801002</td>
    <td>Canada</td>
    <td>Skipper</td>
  </tr>
  <tr class="item">
    <td>user:2901009</td>
    <td>Christchurch</td>
    <td>Alex</td>
  </tr>

</table>
Penny Liu
  • 11,885
  • 5
  • 66
  • 81
0

Found some way to do that with multiple tables and different data types, without external libraries.

https://github.com/VFDouglas/HTML-Order-Table-By-Column/blob/main/index.html

Steps:

  1. Add event listeners to all table headers.
  2. Find the table related to the clicked header and get the order icon.
  3. Declare an object to store the table rows(tr) and an array of values of the selected column.
  4. Iterate the values and check the data type for future sorting.
  5. Sort values and change the table header(th) icon.
  6. Replace the old tbody with the ordered html.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <table>
        <thead>
            <tr>
                <th>Coluna 1 <span>&uarr;</span></th>
                <th>Coluna 2 <span>&uarr;</span></th>
                <th>Coluna 3 <span>&uarr;</span></th>
                <th>Coluna 4 <span>&uarr;</span></th>
                <th>Coluna 5 <span>&uarr;</span></th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>100</td>
                <td>Nome do produto 22</td>
                <td>ABCASD</td>
                <td>22DDS</td>
                <td>454645</td>
            </tr>
            <tr>
                <td>99</td>
                <td>Nome do produto 12</td>
                <td>AACASD</td>
                <td>22DDS</td>
                <td>354645</td>
            </tr>
            <tr>
                <td>300</td>
                <td>Nome do produto 22</td>
                <td>AcCASD</td>
                <td>32DDS</td>
                <td>554649</td>
            </tr>
            <tr>
                <td>400</td>
                <td>Nomde do produto 22</td>
                <td>AcdCASD</td>
                <td>3d2DDS</td>
                <td>554645</td>
            </tr>
            <tr>
                <td>10</td>
                <td>Nome do produto 1</td>
                <td>cCASD</td>
                <td>DDS</td>
                <td>4645</td>
            </tr>
        </tbody>
    </table>
    <br>
    <table>
        <thead>
            <tr>
                <th>Coluna 1 <span>&uarr;</span></th>
                <th>Coluna 2 <span>&uarr;</span></th>
                <th>Coluna 3 <span>&uarr;</span></th>
                <th>Coluna 4 <span>&uarr;</span></th>
                <th>Coluna 5 <span>&uarr;</span></th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>100</td>
                <td>Nome do produto 22</td>
                <td>ABCASD</td>
                <td>22DDS</td>
                <td>454645</td>
            </tr>
            <tr>
                <td>99</td>
                <td>Nome do produto 12</td>
                <td>AACASD</td>
                <td>22DDS</td>
                <td>354645</td>
            </tr>
            <tr>
                <td>300</td>
                <td>Nome do produto 22</td>
                <td>AcCASD</td>
                <td>32DDS</td>
                <td>554649</td>
            </tr>
            <tr>
                <td>400</td>
                <td>Nomde do produto 22</td>
                <td>AcdCASD</td>
                <td>3d2DDS</td>
                <td>554645</td>
            </tr>
            <tr>
                <td>10</td>
                <td>Nome do produto 1</td>
                <td>cCASD</td>
                <td>DDS</td>
                <td>4645</td>
            </tr>
        </tbody>
    </table>
    <script>
        window.onload = function () { // After page loads
            Array.from(document.getElementsByTagName("th")).forEach((element, index) => { // Table headers
                element.addEventListener("click", function (event) {
                    let table = this.closest("table");

                    let order_icon = this.getElementsByTagName("span")[0];
                    let order      = encodeURI(order_icon.innerHTML).includes("%E2%86%91") ? "desc" : "asc";

                    let value_list = {}; // <tr> Object
                    let obj_key    = []; // Values of selected column

                    let string_count = 0;
                    let number_count = 0;

                    table.querySelectorAll("tbody tr").forEach((linha, index_line) => { // <tbody> rows
                        let key = linha.children[element.cellIndex].innerHTML.toUpperCase();
                        key.replace("-", "").match(/^[0-9,.]*$/g) ? number_count++ : string_count++; // Check if value is numeric or string

                        value_list[key + index_line] = linha.outerHTML; // Adding <tr> to object
                        obj_key.push(key + index_line);
                    });

                    if (number_count > 0 && string_count <= 0) { // If all values are numeric
                        obj_key.sort(function(a, b) {
                            return a - b;
                        });
                    }
                    else {
                        obj_key.sort();
                    }

                    if (order == "desc"){
                        obj_key.reverse();
                        order_icon.innerHTML = "&darr;";
                    }
                    else {
                        order_icon.innerHTML = "&uarr;";
                    }

                    let html = "";
                    obj_key.forEach(function (chave) {
                        html += value_list[chave];
                    });
                    table.getElementsByTagName("tbody")[0].innerHTML = html;
                });
            });
        }
    </script>
</body>
</html>
-3

Flexbox-based tables can easily be sorted by using flexbox property "order".

Here's an example:

function sortTable() {
  let table = document.querySelector("#table")
  let children = [...table.children]
  let sortedArr = children.map(e => e.innerText).sort((a, b) => a.localeCompare(b));

  children.forEach(child => {
    child.style.order = sortedArr.indexOf(child.innerText)
  })
}

document.querySelector("#sort").addEventListener("click", sortTable)
#table {
  display: flex;
  flex-direction: column
}
<div id="table">
  <div>Melissa</div>
  <div>Justin</div>
  <div>Judy</div>
  <div>Skipper</div>
  <div>Alex</div>
</div>
<button id="sort"> sort </button>

Explanation

The sortTable function extracts the data of the table into an array, which is then sorted in alphabetic order. After that we loop through the table items and assign the CSS property order equal to index of an item's data in our sorted array.

handle
  • 5,797
  • 3
  • 46
  • 76
Ivan Ivanov
  • 116
  • 1
  • 10
  • 2
    This could become a substantial solution if you'd elaborate with an original code snippet. – dakab Sep 17 '19 at 19:20
  • agreed, this could be interesting. one potential problem is that as the DOM remains in the same order screen readers may have trouble? I don't know enough to know how they deal with the order property. – Tom P Feb 21 '21 at 19:26