Easiest way to sort DOM nodes?

Viewed 66528

If I have a list like this:

<ul id="mylist">
    <li id="list-item1">text 1</li>
    <li id="list-item2">text 2</li>
    <li id="list-item3">text 3</li>
    <li id="list-item4">text 4</li>
</ul>

What's the easiest way to re-arrange the DOM nodes to my preference? (This needs to happen automatically when the page loads, the list-order preference is gained from a cookie)

E.g.

<ul id="mylist">
    <li id="list-item3">text 3</li>
    <li id="list-item4">text 4</li>
    <li id="list-item2">text 2</li>
    <li id="list-item1">text 1</li>
</ul>
9 Answers

Though there's probably an easier way to do this using a JS Library, here's a working solution using vanilla js.

var list = document.getElementById('mylist');

var items = list.childNodes;
var itemsArr = [];
for (var i in items) {
    if (items[i].nodeType == 1) { // get rid of the whitespace text nodes
        itemsArr.push(items[i]);
    }
}

itemsArr.sort(function(a, b) {
  return a.innerHTML == b.innerHTML
          ? 0
          : (a.innerHTML > b.innerHTML ? 1 : -1);
});

for (i = 0; i < itemsArr.length; ++i) {
  list.appendChild(itemsArr[i]);
}

Use ES6 syntax to re-sort children:

var list = document.querySelector('#test-list');

[...list.children]
  .sort((a,b)=>a.innerText>b.innerText?1:-1)
  .forEach(node=>list.appendChild(node));

You might find that sorting the DOM nodes doesn't perform well. A different approach would be to have in your javascript an array that represents the data that would go into the DOM nodes, sort that data, and then regenerate the div that holds the DOM nodes.

Maybe you dont' have that many nodes to sort, so it wouldn't matter. My experience is based on trying to sort HTML tables by manipulating the DOM, including tables with hundreds of rows and a couple dozen columns.

The neatest way I can think of:

The param compare is just like the compare function used in Array.sort().

Sort child nodes.

/**
 * @param {!Node} parent
 * @param {function(!Node, !Node):number} compare
 */
function sortChildNodes(parent, compare) {
  const moveNode = (newParent, node) => {
    // If node is already under a parent, append() removes it from the
    // original parent before appending it to the new parent.
    newParent.append(node);
    return newParent;
  };
  parent.append(Array.from(parent.childNodes) // Shallow copies of nodes.
                    .sort(compare) // Sort the shallow copies.
                    .reduce(moveNode, document.createDocumentFragment()));
}

Sort child elements (a subset of child nodes).

/**
 * @param {!Element} parent
 * @param {function(!Element, !Element):number} compare
 */
function sortChildren(parent, compare) {
  const moveElement = (newParent, element) => {
    // If element is already under a parent, append() removes it from the
    // original parent before appending it to the new parent.
    newParent.append(element);
    return newParent;
  };
  parent.append(Array.from(parent.children) // Shallow copies of elements.
                    .sort(compare) // Sort the shallow copies.
                    .reduce(moveElement, document.createDocumentFragment()));
}
Related