Easiest way to sort DOM nodes?
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 is the easiest way to reconfigure DOM nodes according to my preferences? (This should happen automatically when the page loads, preference in list order is obtained from the cookie)
eg.
<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> Although there may be an easier way to do this using the JS library, the solution using vanilla js works here.
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]); } You may find that sorting DOM nodes does not work well. Another approach would be to have your javascript have an array representing the data that will fall into the DOM nodes, sort that data and then restore the div that contains the DOM nodes.
Maybe you donβt have many nodes to sort, so it doesnβt matter. My experience is based on trying to sort HTML tables by manipulating the DOM, including tables with hundreds of rows and several tens of columns.
See in action: http://jsfiddle.net/stefek99/y7JyT/
jQuery.fn.sortDomElements = (function() { return function(comparator) { return Array.prototype.sort.call(this, comparator).each(function(i) { this.parentNode.appendChild(this); }); }; })(); Terse
If you are already using jQuery, I would recommend tinysort: http://tinysort.sjeiti.com/
$("li").tsort({order:"asc"}); $("li").tsort({order:"desc"}); My version, I hope, will be useful for others:
var p = document.getElementById('mylist'); Array.prototype.slice.call(p.children) .map(function (x) { return p.removeChild(x); }) .sort(function (x, y) { return /* sort logic */; }) .forEach(function (x) { p.appendChild(x); }); Here is the ES6 function for sorting DOM nodes:
const sortChildren = ({ container, childSelector, getScore }) => { const items = [...container.querySelectorAll(childSelector)]; items .sort((a, b) => getScore(b) - getScore(a)) .forEach(item => container.appendChild(item)); }; Here's how you could use it to sort Unallocated user reviews by account :
sortChildren({ container: document.querySelector("#main-stream"), childSelector: ".item", getScore: item => { const rating = item.querySelector(".rating"); if (!rating) return 0; const scoreString = [...rating.classList].find(c => /r\d+/.test(c)); const score = parseInt(scoreString.slice(1)); return score; } }); without analyzing too much if this brings something new to the table, I usually use this:
function forEach(ar, func){ if(ar){for(var i=ar.length; i--; ){ func(ar[i], i); }} } function removeElement(node){ return node.parentNode.removeChild(node); } function insertBefore(ref){ return function(node){ return ref.parentNode.insertBefore(node, ref); }; } function sort(items, greater){ var marker = insertBefore(items[0])(document.createElement("div")); //in case there is stuff before/after the sortees forEach(items, removeElement); items.sort(greater); items.reverse(); //because the last will be first when reappending forEach(items, insertBefore(marker)); removeElement(marker); } where item is an array of children of the same parent. we remove the beginning from the last and add the beginning from the first to avoid flickering at the top, which is probably on the screen. I usually get my array of elements as follows:
forEachSnapshot(document.evaluate(..., 6, null), function(n, i){ items[i] = n; }); Use es6 syntax for resort kids:
var list = $('#test-list')[0] var arr =[]; for(let i=0;i<list.children.length;i++){ arr.push(list.children[i]) } arr.sort((a,b)=>a.innerText>b.innerText) arr.map(node=>list.appendChild(node))