Search code examples
javascripthtmlsortinghtml-tableline-breaks

Sort table, but ignore line breaks and previous spaces


I am using the current JavaScript code to sort text in tables, however sometimes the html editor adds line breaks for long lines, and when the word in the code starts in a new line, the sorting doesn't work properly (column 2 in the example)

How can the JS code be fixed to work around such issue?

The current working code:

window.onload = function() {
  document.querySelectorAll('th').forEach((element) => { // Table headers
    element.addEventListener('click', function() {
      let table = this.closest('table');

      // If the column is sortable
      if (this.querySelector('span')) {
        let order_icon = this.querySelector('span');
        let order = encodeURI(order_icon.innerHTML).includes('%E2%86%91') ? 'desc' : 'asc';
        let separator = '-----'; // Separate the value of it's index, so data keeps intact

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

        let string_count = 0;
        let number_count = 0;

        // <tbody> rows
        table.querySelectorAll('tbody tr').forEach((line, index_line) => {
          // Value of each field
          let key = line.children[element.cellIndex].textContent.toUpperCase();

          // Check if value is date, numeric or string
          if (line.children[element.cellIndex].hasAttribute('data-timestamp')) {
            // if value is date, we store it's timestamp, so we can sort like a number
            key = line.children[element.cellIndex].getAttribute('data-timestamp');
          } else if (key.replace('-', '').match(/^[0-9,.]*$/g)) {
            number_count++;
          } else {
            string_count++;
          }

          value_list[key + separator + index_line] = line.outerHTML.replace(/(\t)|(\n)/g, ''); // Adding <tr> to object
          obj_key.push(key + separator + index_line);
        });
        if (string_count === 0) { // If all values are numeric
          obj_key.sort(function(a, b) {
            return a.split(separator)[0] - b.split(separator)[0];
          });
        } 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;
      }
    });
  });
}
<div align="center">
  <table border="1">
    <thead>
      <tr class="header">
        <th>Title <span>&uarr;</span></th>
        <th>Title2 <span>&uarr;</span></th>
      </tr>
    </thead>
    <tr>
      <td>text</td>
      <td>ear</td>
    </tr>
    <tr>
      <td>arabic</td>
      <td>
        cat</td>
    </tr>
    <tr>
      <td>words</td>
      <td>
        dark</td>
    </tr>
    <tr>
      <td>here</td>
      <td>black</td>
    </tr>
  </table>
</div>


Solution

  • You could apply .trim() to the keys, like here:

    let key = line.children[element.cellIndex].textContent.toUpperCase().trim();
                                                                       //^^^^^\\