Sorting a list by data-attribute

This works for any number of lists: it basically gathers all lis in uls that have your attribute, sorts them according to their data-* attribute value and re-appends them to their parent.

Array.from(document.querySelectorAll("ul > li[data-azsort]"))
  .sort(({dataset: {azsort: a}}, {dataset: {azsort: b}}) => a.localeCompare(b)) // To reverse it, use `b.localeCompare(a)`.
  .forEach((item) => item.parentNode.appendChild(item));
<ul>
  <li data-azsort="skeetjon">
    <a href="#"><span class="list-name">Jon Skeet</span></a>
    <span class="list-desc">Stack Overflow user</span>
  </li>
  <li data-azsort="smithjohn">
    <a href="#"><span class="list-name">John Smith</span></a>
    <span class="list-desc">Professor</span>
  </li>
  <li data-azsort="barnestom">
    <a href="#"><span class="list-name">Tom Barnes</span></a>
    <span class="list-desc">Lecturer</span>
  </li>
</ul>
<ul>
  <li data-azsort="smithjohn">
    <a href="#"><span class="list-name">John Smith</span></a>
    <span class="list-desc">Professor</span>
  </li>
  <li data-azsort="barnestom">
    <a href="#"><span class="list-name">Tom Barnes</span></a>
    <span class="list-desc">Lecturer</span>
  </li>
  <li data-azsort="skeetjon">
    <a href="#"><span class="list-name">Jon Skeet</span></a>
    <span class="list-desc">Stack Overflow user</span>
  </li>
</ul>

The funny thing is, it gets all lis in the same array, sorts them all, but in the end figures out which list the li originally belonged to. It’s a pretty simple and straight-forward solution.

If you want to sort elements by a numeric data attribute, then use this sort function instead:

// Presumably, the data-* attribute won’t be called `azsort`. Let’s call it `numsort`.
({dataset: {numsort: a}}, {dataset: {numsort: b}}) => Number(a) - Number(b) // `Number(b) - Number(a)` to reverse the sort.

A slightly longer ECMAScript 5.1 alternative would be:

Array.prototype.slice.call(document.querySelectorAll("ul > li[data-azsort]")).sort(function(a, b) {
  a = a.getAttribute("data-azsort");
  b = b.getAttribute("data-azsort");

  return a.localeCompare(b);
}).forEach(function(node) {
  node.parentNode.appendChild(node);
});

Leave a Comment