gif gif

The interesting corner

gif gif

Adding a sort option to the hardware page: another example that doing it yourself is often better

I wanted to add some sorting functionality to the hardware page for some time now. first, I decided on using an external library, as there are many options for this. I first tried sorttable.js. That gave me an error about jquery not being found (true, I don't like jquery). So I installed JQuery using npm. That resulted in a warning about npm having a new version


npm notice
npm notice New major version of npm available! 10.8.2 -> 11.3.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.3.0
npm notice To update run: npm install -g npm@11.3.0
npm notice
      
      

So, like the good developer I am, I upgraded. However, this gave an error:


> npm install -g npm@11.3.0
npm error code EBADENGINE
npm error engine Unsupported engine
npm error engine Not compatible with your version of node/npm: npm@11.3.0
npm error notsup Not compatible with your version of node/npm: npm@11.3.0
npm error notsup Required: {"node":"^20.17.0 || >=22.9.0"}
npm error notsup Actual:   {"npm":"10.8.2","node":"v21.7.2"}
npm error A complete log of this run can be found in: /home/sem/.npm/_logs/2025-04-17T19_35_28_170Z-debug-0.log
    

-_-

Naturally, I went on a little detour to get that fixed, but that didn't work. Eventually I remembered I use nvm to manage my node versions, so it was just a nvm install latest to upgrade.

After that, I still got the error about jquery (>人<;). I said "fuck sorttable.js" and tried DataTables. This was supposed to also be a quick fix, and it worked okay, but it broke the category selection
(╯°□°)╯︵ ┻━┻.

So again, I thought "fuck that" and just implemented my own version.

DIY

The only thing I wanted to do was to be able to sort the data based on the hardware item name, type, date or manufacturer. I added a <select> item for those sort types, and made it call the sortTable() function, which calls the updateCategory() function that is also called when a new category is selected. This requests the data from the database, and filters it based on the category name. It then fills the table with the received data. I just updated that function with a part that checks the value of the sorting selector and sorts the data using the JS compareFn functionality:


function fill_data(data) {
  console.log(data);

  var sort_by = document.getElementById("hw_sort");
  var sort_by_value = sort_by.options[sort_by.selectedIndex].value;
  console.log(sort_by_value);

  // actual sorting
  data.sort((a, b) => {
      if (sort_by_value == "name") {
          return a.name.localeCompare(b.name);
      } else if (sort_by_value == "date") {
          return new Date(b.date) - new Date(a.date);
      } else if (sort_by_value == "manufacturer") {
          return a.manufacturer.localeCompare(b.manufacturer);
      } else if (sort_by_value == "type") {
          return a.type.localeCompare(b.type);
      }
  });

  var table = document.getElementById("hardwaretable");

  // Clear existing thead and tbody
  table.querySelector("thead").innerHTML = "";
  table.querySelector("tbody").innerHTML = "";

  // Fill thead
  var thead = table.querySelector("thead");
  var headerRow = document.createElement("tr");
  headerRow.innerHTML = "<t>>Hardware topics</th><th>Date</th>";
  thead.appendChild(headerRow);

  // Fill tbody
  var tbody = table.querySelector("tbody");

  for (var i = 0; i < data.length; i++) {
      var row = document.createElement("tr");

      var cellname = document.createElement("td");
      cellname.innerHTML = `<a href="/hardware/${data[i].entryID}">${data[i].manufacturer} ${data[i].name} ${data[i].type}</a>`;
      row.appendChild(cellname);

      var celldate = document.createElement("td");
      var onlydate = data[i].date.substr(0, 10);
      var newdate = onlydate.substring(8, 10) + "-" + onlydate.substring(5, 7) + "-" + onlydate.substring(0, 4);
      celldate.innerHTML = newdate;
      row.appendChild(celldate);

      tbody.appendChild(row);
  }
}

function updateCategory() {
    var mylist = document.getElementById("hw_categories");
    var table = mylist.options[mylist.selectedIndex].value.toLowerCase().replace(" ", "_");
    const url = '/db/hardware-cat/' + table
    console.log(url);
    fetch(url, { method: "GET" })
        .then(res => res.json())
        .then(data => {
            fill_data(data);
        });
}

function sortTable() {
  updateCategory();
}

const URL = '/db/hardware';
fetch(URL, { method: "GET" })
  .then(res => res.json())
  .then(data => {
      fill_data(data);
  });

var spinner = document.getElementById("hw_categories");
  // create options elements
  const url = '/db/hardware-cat';
  fetch(url, { method: "GET" })
      .then(res => res.json())
      .then(data => {
          console.log(data);
          for (var i = 0; i < data.length; i++) {
              var opt = document.createElement("option");
              opt.value = data[i].name;
              opt.text = data[i].name;
              spinner.appendChild(opt);
          }
      });