Sort checkbox(checked and unchecked) in table

Viewed 79

I want to sort my checkbox when i click on the X:

enter image description here

JS to sort my checkbox(checked and unchecked)?

I got no idea how to write it. please help. The following code is borrowed. The Price and stock value will be pass from other JS file using router.

But for now I make it simple because I want to know how to sort the checkbox.

 var sortedPrice = false;

    function sortPrice() {
        $('#myTable').append(
        $('#myTable').find('tr.item').sort(function (a, b) {
            var td_a = $($(a).find('td.sortPrice')[0]);
            var td_b = $($(b).find('td.sortPrice')[0]);
            if(sortedPrice){
                if(td_a.html() == 'Free') return -1;
                return td_b.html().replace(/\D/g, '') - td_a.html().replace(/\D/g, '');
            }else{
                if(td_a.html() == 'Free') return 1;
                return td_a.html().replace(/\D/g, '') - td_b.html().replace(/\D/g, '');
            }
        })
    );
    if(sortedPrice) sortedPrice = false;
    else sortedPrice = true;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table" id="myTable">
        <tr>
          <th onclick="sortPrice()">Price</th>
          <th>Stock</th>
          <th>%</th>
          <th>X</th>
        </tr>
        <tr class="item">
          <td class="sortPrice">1</td>
          <td>1</td>
          <td>2</td>
          <td><input type="checkbox" value="1"></td>
        </tr>
        <tr class="item">
          <td class="sortPrice">4</td>
          <td>3</td>
          <td>1</td>
          <td><input type="checkbox" value="2"></td>
        </tr>
        <tr class="item">
          <td class="sortPrice">7</td>
          <td>4</td>
          <td>6</td>
          <td><input type="checkbox" value="3"></td>
        </tr>
        <tr class="item">
          <td class="sortPrice">2</td>
          <td>7</td>
          <td>8</td>
          <td><input type="checkbox" value="4"></td>
        </tr>
        <tr class="item">
          <td class="sortPrice">3</td>
          <td>4</td>
          <td>2</td>
          <td><input type="checkbox" value="5"></td>
        </tr>
</table>

2 Answers

I would try to make the click handler generic by taking the following steps:

  • Create a function that takes an array of pairs, and sorts that array by the first value in every pair, and returns the sorted array with just the second value from each pair in sorted order. This generic function can be used to pass pairs of cell-content and corresponding row element. This function could also take care of reversing the order when the input pairs were already sorted.

  • Create a single click handler for the td elements (the column headers). Let it collect the cells in the corresponding column, and for each cell determine whether the checkbox state should be taken as value, or the text content of that cell.

  • After sorting the values in the column with the first function, the rows can be fed into the table again.

  • Use the compare function from Intl.Collator so to have numeric sort when appropriate.

This way you can do away with some of the HTML (onclick, sortPrice, item, ...)

const {compare} = new Intl.Collator(undefined, {numeric: true});

function sortSecondByFirst(pairs) {
    const sorted = [...pairs].sort(([a], [b]) => compare(a, b))
                .map(([,a]) => a);
    if (pairs.every(([,a], i) => a === sorted[i])) {
        sorted.reverse(); // Was already sorted
    }
    return sorted;
}

$("th", "#myTable").click(function () {
    sortColumn($(this).index());
});

function sortColumn(colIdx) {
    const $cells = $(`tr > td:nth-child(${colIdx+1})`, "#myTable");
    $("#myTable").append(
        sortSecondByFirst($cells.get().map((cell) => {
            const $input = $('input[type=checkbox]', cell);
            const value = $input.length ? $input.prop("checked") : $(cell).text();
            return [
                value,
                $(cell).parent()
            ];
        }))
    );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myTable">
    <tr>
      <th>Price</th><th>Stock</th><th>%</th><th>X</th>
    </tr>
    <tr>
      <td>1</td><td>1</td><td>2</td>
      <td><input type="checkbox" value="1"></td>
    </tr>
    <tr>
      <td>4</td><td>3</td><td>1</td>
      <td><input type="checkbox" value="2"></td>
    </tr>
    <tr>
      <td>7</td><td>4</td><td>6</td>
      <td><input type="checkbox" value="3"></td>
    </tr>
    <tr>
      <td>20</td><td>7</td><td>8</td>
      <td><input type="checkbox" value="4"></td>
    </tr>
    <tr>
      <td>3</td><td>4</td><td>2</td>
      <td><input type="checkbox" value="5"></td>
    </tr>
</table>

Quite honestly if u have a choice I'd always go use Vue, react or the like as a ui framework. There this is simpler and u have a better -in my eyes - split of html template and data. Vue is quite easy to learn from my experience too.(great tutorials eg on YouTube)

That said in jQuery I guess I would write a sort function like the one u got there that via onclick event it triggered when X is clicked on and for the sorting write a similar compare function as above. Eg

(a,b) =>  a.checked - b.checked;

Hope this makes sense to you or where precisely do u struggle?

Related