javascriptsortinglist.js

list.js - Custom sort function on button click without jQuery


List.js without jQuery. It's working as supplied out of the box.

Mission:

When a 'List By Price' button is clicked, sold-out items need to display at the bottom of the sorted list - regardless of ascending or descending.

I've begun to develop a customer sort().

    list.sort('price', {
      order: 'asc',
      sortFunction: function (a, b) {
        console.log('sorting price');
       // sort mechanics here
      }
  });

However, it executes when list.js initialises (not wanted) and doesn't execute when the button is pressed (wanted).


EDIT: Working code...

NOTE ---> listjs.com

var options = {
  valueNames: [ 'price' ]
};

var userList = new List('for-sale', options);
body {
  font-family:sans-serif;
  font-size:18px;
}
td {
  padding:10px; 
}
.sold, .red{
  font-weight:bold;
  color:red;
}
.intro + .intro{
  border-bottom:1px solid #000;
  padding-bottom: 1rem;
  margin-bottom: 2rem;
}
<p class="intro"><span class="red">Sold out</span> items should ALWAYS appear at the bottom of the list after being sorted - regardless of ascending or descending sort.</p><p class="intro">The button toggles ascending and descending</p>
<div id="for-sale">
  <button class="sort" data-sort="price">
    Sort by price
  </button>
  <table>
    <!-- IMPORTANT, class="list" have to be at tbody -->
    <tbody class="list">
      <tr>
        <td class="price sold">Sold out</td>
      </tr>
      <tr>
        <td class="price">90</td>
      </tr>
      <tr>
        <td class="price">10</td>
      </tr>
      <tr>
        <td class="price sold">Sold out</td>
      </tr>
      <tr>
        <td class="price">30</td>
      </tr>
      <tr>
        <td class="price">70</td>
      </tr>
      <tr>
        <td class="price">50</td>
      </tr>
    </tbody>
  </table>

</div>

<script src="//cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script>


Solution

  • The list.js plugin does not support exceptions on the sorting. And sadly, re-ingineering it is not an option that I retain.


    Calling the .sort() function on the instance will simply trigger a sort again... Maybe with a custom sortFunction... But that is not the key of the issue here.

    You want to partially sort the list and I can't imagine any custom sortFunction to do this.


    But! you can re-position some elements after the plugin has correctly its job. Fortunately, there is no delay (due to any effect) on the re-ordering made by list.js, so you don't need any setTimeout that would be noticable.

    You simply need to register an additional event listener. Event listeners execute in the order they where registered... So the one below will execute after the list.js one.

    // Code slightly adapted from the example on the list.js website
    var options = {
      valueNames: ["price"]
    };
    var userList = new List("for-sale", options);
    
    
    // Suggested solution for your issue
    
    // Get the list element
    let list = document.querySelector(".list");
    
    // Add an event listener on the sort button
    document.querySelector(".sort").addEventListener("click", () => {
    
      // Get an array of all the rows, based on the 'sold' class
      let rows = Array.from(list.querySelectorAll("tr"));
    
      // Get just the sold out ones
      let soldout = rows.filter((r) => r.querySelector(".sold"));
    
      // Remove all sold out rows, based on the 'sold' class
      list.querySelectorAll("sold").forEach((s) => s.closest("tr").remove());
    
      // Re-append them at the end of the list
      soldout.forEach((s) => list.append(s));
    });
    body {
      font-family: sans-serif;
      font-size: 18px;
    }
    
    td {
      padding: 10px;
    }
    
    .sold,
    .red {
      font-weight: bold;
      color: red;
    }
    
    .intro+.intro {
      border-bottom: 1px solid #000;
      padding-bottom: 1rem;
      margin-bottom: 2rem;
    }
    <p class="intro"><span class="red">Sold out</span> items should ALWAYS appear at the bottom of the list after being sorted - regardless of ascending or descending sort.</p>
    <p class="intro">The button toggles ascending and descending</p>
    <div id="for-sale">
      <button class="sort" data-sort="price">
        Sort by price
      </button>
      <table>
        <!-- IMPORTANT, class="list" have to be at tbody -->
        <tbody class="list">
          <tr>
            <td class="price sold">Sold out</td>
          </tr>
          <tr>
            <td class="price">90</td>
          </tr>
          <tr>
            <td class="price">10</td>
          </tr>
          <tr>
            <td class="price sold">Sold out</td>
          </tr>
          <tr>
            <td class="price">30</td>
          </tr>
          <tr>
            <td class="price">70</td>
          </tr>
          <tr>
            <td class="price">50</td>
          </tr>
        </tbody>
      </table>
    
    </div>
    
    <script src="//cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script>