To sort elements efficiently (all at once and with minimal DOM interruption), we need to:
<ul id='my-color-list'>
<li class="disabled">Red</li>
<li>Green</li>
<li class="disabled">Purple</li>
<li>Orange</li>
</ul>
Find them - .children()
or .find()
This will give us back an Array-like object to play with.
var $myColorList = $('#my-color-list');
// Elements one layer deep get .children(), any deeper go with .find()
var $colors = $myColorList.children('li');
Re-arrange them - Array.prototype.sort()
This is currently setup to return the elements in Ascending order based on the HTML content (aka their colors).
/**
* Bind $colors to the sort method so we don't have to travel up
* all these properties more than once.
*/
var sortList = Array.prototype.sort.bind($colors);
sortList(function ( a, b ) {
// Cache inner content from the first element (a) and the next sibling (b)
var aText = a.innerHTML;
var bText = b.innerHTML;
// Returning -1 will place element `a` before element `b`
if ( aText < bText ) {
return -1;
}
// Returning 1 will do the opposite
if ( aText > bText ) {
return 1;
}
// Returning 0 leaves them as-is
return 0;
});
Insert them - .append()
Note that we don't need to detach the elements first - append()
will move elements that already exist in the DOM, so we won't have extra copies
// Put it right back where we got it
$myColorList.append($colors);
<!-- previous HTML above -->
<button type='button' id='btn-sort'>
Sort
</button>
var ascending = true;
sortList()
out here to minimize our DOM processingvar $myColorList = $('#my-color-list');
var $colors = $myColorList.children('li');
var sortList = Array.prototype.sort.bind($colors);
doSort()
function// Put the sortList() and detach/append calls in this portable little thing
var doSort = function ( ascending ) {
sortList(function ( a, b ) {
// ...
});
$myColorList.append($colors);
};
$('#btn-sort')
$('#btn-sort').on('click', function () {
// Run the sort and pass in the direction value
doSort(ascending);
// Toggle direction and save
ascending = !ascending;
});
var ascending = true;
var $myColorList = $('#my-color-list');
var $colors = $myColorList.children('li');
var sortList = Array.prototype.sort.bind($colors);
var doSort = function ( ascending ) {
sortList(function ( a, b ) {
var aText = a.innerHTML;
var bText = b.innerHTML;
if ( aText < bText ) {
return ascending ? -1 : 1;
}
if ( aText > bText ) {
return ascending ? 1 : -1;
}
return 0;
});
$myColorList.append($colors);
};
$('#btn-sort').on('click', function () {
doSort(ascending);
ascending = !ascending;
});
Bonus
// ...
var doSort = function ( ascending ) {
sortList(function ( a, b ) {
// ...initial sorting...
}).sort(function ( a, b ) {
// We take the returned items and sort them once more
var aClass = a.className;
var bClass = b.className;
// Let's group the disabled items together and put them at the end
/**
* If the two elements being compared have the same class
* then there's no need to move anything.
*/
if ( aClass !== bClass ) {
return aClass === 'disabled' ? 1 : -1;
}
return 0;
});
// And finalize with re-insert
$myColorList.append($colors);
};
// ...
Can you take it one step further?