7

I have this HTML code:

<div id="main">
  <div id="dv_7">...</div>
  <div id="dv_1">...</div>
  <div id="dv_8">...</div>
  <div id="dv_4">...</div>
  <div id="dv_11">...</div>
  <div id="dv_2">...</div>
</div>

How to order the divs in the maindiv with javascript? I have no idea :(

thanks in advance,

7 Answers 7

8

Hope this helps. Updated the id to account for alphabetical ordering 1 and 11.

<div id="main">
  <div id="dv_07">7...</div>
  <div id="dv_01">1...</div>
  <div id="dv_08">8...</div>
  <div id="dv_04">4...</div>
  <div id="dv_11">11...</div>
  <div id="dv_02">2...</div>
</div>​

jQuery option:

var mylist = $('#main');
var listitems = mylist.children('div').get();
listitems.sort(function(a, b) {
    var compA = $(a).attr('id').toUpperCase();
    var compB = $(b).attr('id').toUpperCase();
    return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
})
$.each(listitems, function(idx, itm) {
    mylist.append(itm);
});​

Javascript option:

var mylist = document.getElementById('main');
var divs = mylist.getElementsByTagName('div');
var listitems = [];
for (i = 0; i < divs.length; i++) {
        listitems.push(divs.item(i));
}
listitems.sort(function(a, b) {
    var compA = a.getAttribute('id').toUpperCase();
    var compB = b.getAttribute('id').toUpperCase();
    return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
});
for (i = 0; i < listitems.length; i++) {
    mylist.appendChild(listitems[i]);
}​
Sign up to request clarification or add additional context in comments.

1 Comment

getElementsByTagName('div') will only return div elements, so the nodeType test is redundant.
7

How about:

var main = document.getElementById( 'main' );

[].map.call( main.children, Object ).sort( function ( a, b ) {
    return +a.id.match( /\d+/ ) - +b.id.match( /\d+/ );
}).forEach( function ( elem ) {
    main.appendChild( elem );
});

Live demo: http://jsfiddle.net/ZEKrH/6/

(You'll need to shim those array methods for IE8.)

24 Comments

Can you set a NodeList as the calling context for Array methods in IE8? ...or I suppose it wouldn't matter since they're shimmed! :P
@amnotiam Yes. Adding ES5-shim will make my demo work in IE8: jsfiddle.net/ZEKrH/1
@jfriend00 .children does exist in IE6-8, but it also includes comment nodes (which shouldn't be an issue in this application). IE7 has only 3-5% left, and should die soon. If IE7 support is required, one should use a cross-browser library. It's not feasible to manually polyfill that browser (because there is just too much to fix).
@amnotiam Ah, of course. DOM selection is not needed since we already have all references inside main.children. I've further simplified the code.
@amnotiam Yes, you are right. [].slice.call( nodeList ) does not work in IE7/8. [].map.call(main.children, Object) does work in those browsers - it's a nice hack.
|
2

For a solution that works for any arbitrary number of child divs with numbers in any range, you can use a function like this (that actually parses the number of our the ID and does a true numeric sort on it):

function sortChildrenDivsById(parentId) {
    var parent = document.getElementById(parentId);
    // get child divs
    var children = parent.getElementsByTagName("div");
    var ids = [], obj, i, len;
    // build an array of objects that has both the element 
    // and a parsed div number in it so we can sort
    for (i = 0, len = children.length; i < len; i++) {
        obj = {};
        obj.element = children[i];
        obj.idNum = parseInt(children[i].id.replace(/[^\d]/g, ""), 10);
        ids.push(obj);
    }
    // sort the array
    ids.sort(function(a, b) {return(a.idNum - b.idNum);});
    // append in sorted order
    for (i = 0; i < ids.length; i++) {
         parent.appendChild(ids[i].element);
    }
}

Working example here: http://jsfiddle.net/jfriend00/v9mCM/

FYI, this is cross-browser, plain javascript and will even work in old browsers without shims.


Here's another way of doing it with slightly less code:

function sortChildrenDivsById(parentId) {
    var parent = document.getElementById(parentId);
    var children = parent.getElementsByTagName("div");
    var ids = [], i, len;
    for (i = 0, len = children.length; i < len; i++) {
        ids.push(parseInt(children[i].id.replace(/^.*_/g, ""), 10));
    }
    ids.sort(function(a, b) {return(a - b);});
     for (i = 0, len = ids.length; i < len; i++) {
         parent.appendChild(document.getElementById("dv_" + ids[i]));
     }
}

Working example: http://jsfiddle.net/jfriend00/TqJVb/

All the ids nums are parsed out and put into an array which is sorted and then each object is looked up by id and reinserted in sorted order. This wouldn't be quite as fast as the first one, but it's less code.

Comments

2

the following might work:

var main = document.getElementById("main");
for(var i = 11; i > -1; i--) {
    var div = document.getElementById("dv_" + i);
    if(div != null)
        main.appendChild(div);
}

4 Comments

There should be if(div != null).
And document.getElementById("main"); I think.
A scoped query performs better: var div = main.querySelector("#dv_" + i);
This assumes there are no dv_nn ids anywhere else in the document and it requires hard coding an upper bound for the numbers rather than just sorting the items that are there, no matter how many there are.
1

The following is compatible with browsers back to IE 5 and similar, no shims or libraries. The sort function can be modified to sort numerically, at present it will sort the divs as 1, 11, 2, 4, etc. It's not too hard to change it so they are sorted 1, 2, 4, ... 11.

function sortDivs(div) {
  var divs = div.getElementsByTagName('div');
  var a = [];
  for (var i=0, iLen=divs.length; i<iLen; i++) { 
    a[i] = divs[i];
  }
  a.sort(function(a, b) {
    return a.id < b.id? -1 : a.id == b.id? 0 : 1;
  });
  while (iLen--) {
    div.insertBefore(a[iLen], div.firstChild);
  }
}

window.onload = function() {
  sortDivs(document.getElementById('main'));
}

Edit

Minimalist version for those who think it matters with comments and numeric sort.

function sortDivs(div) {
  var divs = div.getElementsByTagName('div');

  // Convert divs collection to an array
  for (var i=0, iLen=divs.length, a=[]; i<iLen; i++) a[i] = divs[i];

  // Sort the array numerically
  a.sort(function(a, b) {
    return a.id.split('_')[1] - b.id.split('_')[1]; 
  });

  // Move elements to sorted order
  while (iLen--) div.insertBefore(a[iLen], div.firstChild);
}

Comments

0

2021 answer

function sortChildren(parent, comparator) {
    parent.replaceChildren(...Array.from(parent.children).sort(comparator));
}

That's all you need. Example:

const main = document.getElementById('main');
sortChildren(main, (a, b) => +a.id.match( /\d+/ ) - +b.id.match( /\d+/ ));

Comments

0
<div id="main">
  <div id="dv_7" data-order=7>7</div>
  <div id="dv_1" data-order=1>1</div>
  <div id="dv_8" data-order=8>8</div>
  <div id="dv_4" data-order=4>4</div>
  <div id="dv_11" data-order=11>11</div>
  <div id="dv_2" data-order=2>2</div>
</div>

<button onclick="sort()">
Sort
</button>

function sort() {

  var main = document.getElementById( 'main' );

  [].map.call( main.children, Object ).sort( function ( a, b ) {
console.log(a.dataset.order);
      return +a.dataset.order - +b.dataset.order;
  }).forEach( function ( elem ) {
      main.appendChild( elem );
  });

}

Updated @Šime Vidas answer to support dynamic order with button and Data Attribute

http://jsfiddle.net/hbe4w90s/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.