'Sort HTML elements by data-attribute [duplicate]

I have the following markup:

<ul>
  <li class="category-item" data-category-group="jeans">Bottoms</li>
  <li class="category-item" data-category-group="tops">Shirt</li>
  <li class="category-item" data-category-group="jeans">Jeans</li>
  <li class="category-item" data-category-group="jeans">Shorts</li>
  <li class="category-item" data-category-group="tops">Hoodie</li>
  <li class="category-item" data-category-group="accesories">Sunglasses</li>
</ul>

The elements can have different group names in the data-category-group attribute. I want to be able to sort the elements so that the elements with the group of jeans will all come after each other in the DOM.

I had an idea to try to solve this by turning the HTML collection into an array and then sort them. But its does not seem to be able to work that way.

Here is my JavaScript:

var categoryItems = document.querySelectorAll("[data-category-group]");
var categoryItemsArray = Array.from(categoryItems)

document.getElementById("demo").innerHTML = categoryItemsArray;

function myFunction() {
    categoryItemsArray.sort();
    document.getElementById("demo").innerHTML = categoryItemsArray;
}

How could this be achieved?

Checkout a codepen here: https://codepen.io/fennefoss/pen/PBGrPZ



Solution 1:[1]

You should use Array#sort, just pass it a function that checks the data-category-group property (using String#localeCompare()):

var categoryItems = document.querySelectorAll("[data-category-group]");
var categoryItemsArray = Array.from(categoryItems);

let sorted = categoryItemsArray.sort(sorter);

function sorter(a,b) {
    return a.dataset.categoryGroup.localeCompare(b.dataset.categoryGroup); // sorts based on alphabetical order
}

document.querySelector("button").onclick = () => sorted.forEach(e => document.querySelector("#demo").appendChild(e));
<ul id="demo">
  <li class="category-item" data-category-group="jeans">Bottoms</li>
  <li class="category-item" data-category-group="tops">Shirt</li>
  <li class="category-item" data-category-group="jeans">Jeans</li>
  <li class="category-item" data-category-group="jeans">Shorts</li>
  <li class="category-item" data-category-group="tops">Hoodie</li>
  <li class="category-item" data-category-group="accesories">Sunglasses</li>
</ul>


<button>Sort Elements</button>

Solution 2:[2]

You could do this with sort method on an array and then append back elements to ul.

let ul = document.querySelector("ul");
let li = ul.querySelectorAll("li");

let sorted = Array.from(li).sort((a, b) => {
  return (b.dataset.categoryGroup == 'jeans') - (a.dataset.categoryGroup == 'jeans')
})

ul.innerHTML = "";
sorted.forEach(e => ul.appendChild(e))
<ul>
  <li class="category-item" data-category-group="jeans">Bottoms</li>
  <li class="category-item" data-category-group="tops">Shirt</li>
  <li class="category-item" data-category-group="jeans">Jeans</li>
  <li class="category-item" data-category-group="jeans">Shorts</li>
  <li class="category-item" data-category-group="tops">Hoodie</li>
  <li class="category-item" data-category-group="accesories">Sunglasses</li>
</ul>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Nenad Vracar