4
\$\begingroup\$

I used the following Javascript to sort an unnumbered list of numeric li-tags as follows:

// 1. get the <UL>-element from the BODY
var nList = document.getElementById("allItems");
// 2. extract all the <LI>-elements from that <UL> and put it in a NodeList
var nEntry = nList.getElementsByTagName('li');

// 3. we can't sort a NodeList, so first make it an Array
var nEntryArray = Array.prototype.slice.call(nEntry, 0);

// 4. sort the array, the normal sort()-function won't do because it is an alphabetical sort
// to sort() numeric values, see http://www.w3schools.com/jsref/jsref_sort.asp example, as "Default sort order is alphabetic and ascending. When numbers are sorted alphabetically, "40" comes before "5".  To perform a numeric sort, you must pass a function as an argument when calling the sort method."
// the numeric value of the <LI> nodes can be located in nEntryArray[i].firstChild.nodeValue , so compare those

nEntryArray.sort(function(a,b){
  return a.firstChild.nodeValue - b.firstChild.nodeValue
})

// 5. empty the nList and refill it with those in the correct order at the nEntryArray
while (nList.lastChild)
{
  nList.removeChild(nList.lastChild);
}

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

If a HTML-code is given with a list as such:

<ul id='allItems'>
    <li class="black">100</li> 
    <li id="note10">10</li> 
    <li>1</li> 
    <li>20</li> 
    <li class="order2">16</li> 
</ul> 

it will order the list numerically without omitting the attributes of the <LI>-tags.

It is one of my first JavaScript-attempts, and I was wondering if this is indeed correct or whether it could be simplified. Especially the conversion from Nodelist to Array seems redundant to me, but I haven't found a more gracious solution.

I post this code-block as I was looking on StackOverflow and through Google for a piece of code to help me solve this particular problem, but I couldn't find something that was understandable to a beginner like me. I easily found ways to sort lists , but then the attributes would be omitted and in the end it took me two days (yep, beginner :-)) to come up with this solution.

Any comments?

\$\endgroup\$
2
\$\begingroup\$

There are a few clear improvements I can see when you are reinserting the nodes back into the DOM tree.

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

1) You may benefit from using a documentFragment to build up your elements then submit them all at once to the nList

2) (micro), cache the length of your array in the for loop.

var df = document.createDocumentFragment();
for( var i = 0, l = nEntryArray.length; i < l; i++) {
    df.appendChild(nEntryArray[i]);
}
nList.appendChild(df);

Otherwise I do not see any issues with this code. http://jsfiddle.net/rlemon/faY3Z/

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ thanks for the suggestion (and for rickrolling me at the same time :-)). What is the use of the cache ? \$\endgroup\$ – Wim Aug 28 '12 at 15:49
  • \$\begingroup\$ each iteration of the for loop you recalculate the length of the array, this is costly.. and can lead to unexpected results (if you are modifying the length of the array). By caching the length you don't have to recalculate it each time and if you alter the length within the loop the loop is unaffected. \$\endgroup\$ – rlemon Aug 28 '12 at 19:11
  • \$\begingroup\$ Since length is an attribute and not a method call, would it really be 'recalculating the length of the array' on every access? \$\endgroup\$ – Vikdor Aug 30 '12 at 6:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.