Reverse order of a set of HTML elements
Asked Answered
C

8

20

I have a set of divs that looks like this:

<div id="con">
    <div> 1 </div>
    <div> 2 </div>
    <div> 3 </div>
    <div> 4 </div>
    <div> 5 </div>
</div>

But I want them to flip so that it looks like this:

<div> 5 </div>
<div> 4 </div>
<div> 3 </div>
<div> 2 </div>
<div> 1 </div>

So that when a new <div> is added it goes to the end of the list.

How can I do this (or is there a better way of doing this)?

Congruous answered 30/10, 2011 at 1:17 Comment(1)
"So that when a div is added it will go to the end of the list...." - is your question how to reverse existing elements (some good answers for that below), or how to add new elements in a particular spot? Starting from your desired output, if you added a new <div>6</div> should it go below 1 or above 5?Jamestown
T
20

Wrapped up as a nice jQuery function available on any set of selections:

$.fn.reverseChildren = function() {
  return this.each(function(){
    var $this = $(this);
    $this.children().each(function(){ $this.prepend(this) });
  });
};
$('#con').reverseChildren();

Proof: http://jsfiddle.net/R4t4X/1/

Edit: fixed to support arbitrary jQuery selections

Tartar answered 30/10, 2011 at 13:5 Comment(0)
C
23

A vanilla JS solution:

function reverseChildren(parent) {
    for (var i = 1; i < parent.childNodes.length; i++){
        parent.insertBefore(parent.childNodes[i], parent.firstChild);
    }
}
Chobot answered 16/6, 2016 at 13:25 Comment(1)
This needs more jquery :) +1 for a vanilla version.Oler
T
20

Wrapped up as a nice jQuery function available on any set of selections:

$.fn.reverseChildren = function() {
  return this.each(function(){
    var $this = $(this);
    $this.children().each(function(){ $this.prepend(this) });
  });
};
$('#con').reverseChildren();

Proof: http://jsfiddle.net/R4t4X/1/

Edit: fixed to support arbitrary jQuery selections

Tartar answered 30/10, 2011 at 13:5 Comment(0)
T
17

I found all the above somehow unsatisfying. Here is a vanilla JS one-liner:

parent.append(...Array.from(parent.childNodes).reverse());  

Snippet with explanations:

// Get the parent element.
const parent = document.getElementById('con');
// Shallow copy to array: get a `reverse` method.
const arr = Array.from(parent.childNodes);
// `reverse` works in place but conveniently returns the array for chaining.
arr.reverse();
// The experimental (as of 2018) `append` appends all its arguments in the order they are given. An already existing parent-child relationship (as in this case) is "overwritten", i.e. the node to append is cut from and re-inserted into the DOM.
parent.append(...arr);
<div id="con">
  <div> 1 </div>
  <div> 2 </div>
  <div> 3 </div>
  <div> 4 </div>
  <div> 5 </div>
</div>
Typewriter answered 20/6, 2018 at 12:36 Comment(1)
Instead of Array.from you could just do [...parent.childNodes] too.Miffy
I
6

without a library:

function reverseChildNodes(node) {
    var parentNode = node.parentNode, nextSibling = node.nextSibling,
        frag = node.ownerDocument.createDocumentFragment();
    parentNode.removeChild(node);
    while(node.lastChild)
        frag.appendChild(node.lastChild);
    node.appendChild(frag);
    parentNode.insertBefore(node, nextSibling);
    return node;
}

reverseChildNodes(document.getElementById('con'));

jQuery-style:

$.fn.reverseChildNodes = (function() {
    function reverseChildNodes(node) {
        var parentNode = node.parentNode, nextSibling = node.nextSibling,
            frag = node.ownerDocument.createDocumentFragment();
        parentNode.removeChild(node);
        while(node.lastChild)
            frag.appendChild(node.lastChild);
        node.appendChild(frag);
        parentNode.insertBefore(node, nextSibling);
        return node;
    };
    return function() {
        this.each(function() {
            reverseChildNodes(this);
        });
        return this;
    };
})();

$('#con').reverseChildNodes();

jsPerf Test

Illuviation answered 30/10, 2011 at 5:0 Comment(3)
Yes, also very hard for all to read and thus change and maintain when compared with solution below.Erythro
@Tartar and Michael Durrant: If you prefer more than two reflows than you can this version.Illuviation
@Illuviation is a better solution then accepted answer since it doesn't depend on jQuery, or more importantly cause reflow when dealing with large number of elements.Triplicate
M
3

One way:

function flip(){
 var l=$('#con > div').length,i=1;
 while(i<l){
   $('#con > div').filter(':eq(' + i + ')').prependTo($('#con'));
   i++;
 }
}
Maje answered 30/10, 2011 at 1:38 Comment(1)
This is the one that worked for me because my parent div had other dynamically added child elements and I needed to match exact ones.Reclinate
L
1

I think the easiest is just to use display: flex

#con {
  display: flex;
  flex-direction: column-reverse;
}
<div id="con">
    <div> 1 </div>
    <div> 2 </div>
    <div> 3 </div>
    <div> 4 </div>
    <div> 5 </div>
</div>
Lehmann answered 14/9, 2023 at 16:4 Comment(1)
Just note that this doesn't actually reverse the DOM order, but it would appear to do so to the end user.Zwiebel
K
0

Another (simpler?) vanilla javascript response: http://jsfiddle.net/d9fNv/

var con = document.getElementById('con');
var els = Array.prototype.slice.call(con.childNodes);
for (var i = els.length -1; i>=0; i--) {
    con.appendChild(els[i]);
}

Alternatively, a shorter but less efficient method: http://jsfiddle.net/d9fNv/1/

var con = document.getElementById('con');
Array.prototype.slice.call(con.childNodes).reverse().forEach(function(el) {
    con.appendChild(el);
});
Karl answered 30/10, 2011 at 23:6 Comment(0)
I
0

  const container = document.getElementById("con");
    const divs = Array.from(container.querySelectorAll("div"));
    
    // Reverse the order of the div elements
    divs.reverse();
    
    // Append the reversed divs back to the container
    divs.forEach((div) => {
        container.appendChild(div);
    });
<div id="con">
    <div> 1 </div>
    <div> 2 </div>
    <div> 3 </div>
    <div> 4 </div>
    <div> 5 </div>
    <div> 6 </div>
    <div> 7 </div>
    <div> 0 </div>
</div>
Immemorial answered 14/9, 2023 at 17:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.