chirag goyal
chirag goyal

Reputation: 133

Java script table sorting numeric values

Script giving wrong result for numeric values, how can I fix it to work for both numeric and alphabet?

Here is the javascript I used

function sortTableByColumn(table, column, asc = true) {
    const dirModifier = asc ? 1 : -1;
    const tBody = table.tBodies[0];
    const rows = Array.from(tBody.querySelectorAll("tr"));

    // Sort each row
    const sortedRows = rows.sort((a, b) => {
        const aColText = a.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();
        const bColText = b.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();

        return aColText > bColText ? (1 * dirModifier) : (-1 * dirModifier);
    });

    // Remove all existing TRs from the table
    while (tBody.firstChild) {
        tBody.removeChild(tBody.firstChild);
    }

    // Re-add the newly sorted rows
    tBody.append(...sortedRows);

    // Remember how the column is currently sorted
    table.querySelectorAll("th").forEach(th => th.classList.remove("th-sort-asc", "th-sort-desc"));
    table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-asc", asc);
    table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-desc", !asc);
}

document.querySelectorAll(".table-sortable th").forEach(headerCell => {
    headerCell.addEventListener("click", () => {
        const tableElement = headerCell.parentElement.parentElement.parentElement;
        const headerIndex = Array.prototype.indexOf.call(headerCell.parentElement.children, headerCell);
        const currentIsAscending = headerCell.classList.contains("th-sort-asc");

        sortTableByColumn(tableElement, headerIndex, !currentIsAscending);
    });
});
.table-sortable th {
  cursor: pointer;
}

.table-sortable .th-sort-asc::after {
  content: "\25b4";
}

.table-sortable .th-sort-desc::after {
  content: "\25be";
}

.table-sortable .th-sort-asc::after,
.table-sortable .th-sort-desc::after {
  margin-left: 5px;
}

.table-sortable .th-sort-asc,
.table-sortable .th-sort-desc {
  background: rgba(0, 0, 0, 0.1);
}
<html>
<head><title>Some table</title></head>

<body>
  <table class="table-sortable">
    <thead>
      <tr>
        <th>Roll number</th>
        <th>Name</th>
        <th>Another number</th>
      <tr>
    </thead>
    <tbody>
      <tr><td>34351</td><td>svvfvs</td><td>4551</td></tr>
      <tr><td>99</td><td>ghh</td><td>413</td></tr>
      <tr><td>6455</td><td>fddfbb</td><td>82</td></tr>
      <tr><td>1245</td><td>dfvfdvfdv</td><td>4315</td></tr>
      <tr><td>46130</td><td>fvfvfvf</td><td>8846161</td></tr>
    </tbody>
  </table>
</body>
</html>

The css script is only used for the indication of asc, dec no problem in css though

You can run the code and see the column 1st and the 3rd are just taking 1st character and taking that to sort the numbers too giving wrong result.

Can you please edit the code and post it as a whole, It would really happen. Thanks in advance

Upvotes: 1

Views: 658

Answers (1)

firatozcevahir
firatozcevahir

Reputation: 882

You can simply check if the aColText and bColText are number or string in your sort function

function sortTableByColumn(table, column, asc = true) {
  const dirModifier = asc ? 1 : -1;
  const tBody = table.tBodies[0];
  const rows = Array.from(tBody.querySelectorAll("tr"));

  // Sort each row
  const sortedRows = rows.sort((a, b) => {
    const aColText = a.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();
    const bColText = b.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();
    if (isNaN(parseFloat(aColText)) && isNaN(parseFloat(bColText))) {
      return aColText > bColText ? (1 * dirModifier) : (-1 * dirModifier);
    }
    return +aColText > +bColText ? (1 * dirModifier) : (-1 * dirModifier);
  });

  // Remove all existing TRs from the table
  while (tBody.firstChild) {
    tBody.removeChild(tBody.firstChild);
  }

  // Re-add the newly sorted rows
  tBody.append(...sortedRows);

  // Remember how the column is currently sorted
  table.querySelectorAll("th").forEach(th => th.classList.remove("th-sort-asc", "th-sort-desc"));
  table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-asc", asc);
  table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-desc", !asc);
}

document.querySelectorAll(".table-sortable th").forEach(headerCell => {
  headerCell.addEventListener("click", () => {
    const tableElement = headerCell.parentElement.parentElement.parentElement;
    const headerIndex = Array.prototype.indexOf.call(headerCell.parentElement.children, headerCell);
    const currentIsAscending = headerCell.classList.contains("th-sort-asc");

    sortTableByColumn(tableElement, headerIndex, !currentIsAscending);
  });
});
.table-sortable th {
  cursor: pointer;
}

.table-sortable .th-sort-asc::after {
  content: "\25b4";
}

.table-sortable .th-sort-desc::after {
  content: "\25be";
}

.table-sortable .th-sort-asc::after,
.table-sortable .th-sort-desc::after {
  margin-left: 5px;
}

.table-sortable .th-sort-asc,
.table-sortable .th-sort-desc {
  background: rgba(0, 0, 0, 0.1);
}
<html>

<head>
  <title>Some table</title>
</head>

<body>
  <table class="table-sortable">
    <thead>
      <tr>
        <th>Roll number</th>
        <th>Name</th>
        <th>Another number</th>
        <tr>
    </thead>
    <tbody>
      <tr>
        <td>34351</td>
        <td>svvfvs</td>
        <td>4551</td>
      </tr>
      <tr>
        <td>99</td>
        <td>ghh</td>
        <td>413</td>
      </tr>
      <tr>
        <td>6455</td>
        <td>fddfbb</td>
        <td>82</td>
      </tr>
      <tr>
        <td>1245</td>
        <td>dfvfdvfdv</td>
        <td>4315</td>
      </tr>
      <tr>
        <td>46130</td>
        <td>fvfvfvf</td>
        <td>8846161</td>
      </tr>
    </tbody>
  </table>
</body>

</html>

Upvotes: 1

Related Questions