60

What is the best way to reverse the order of child elements with jQuery.

For example, if I start with:

<ul> <li>A</li> <li>B</li> <li>C</li> </ul> 

I want to end up with this:

<ul> <li>C</li> <li>B</li> <li>A</li> </ul> 
2
  • are you doing a sorting type of thing? If not you can do something like this api.jquery.com/get Commented Mar 18, 2011 at 3:50
  • I'm not really sorting here, but I have a separate task that will involve sorting. Thanks for the tip. Commented Mar 18, 2011 at 16:52

6 Answers 6

142
var list = $('ul'); var listItems = list.children('li'); list.append(listItems.get().reverse()); 
Sign up to request clarification or add additional context in comments.

8 Comments

I never noticed this answer before now, but I'll agree that it's better than my answer. Mine just illustrates an interesting property of append/prepend.
Short and sweet. One question: What's the difference between listItems.reverse(); and listItems.get().reverse()? I don't understand why the first one doesn't work, isn't ListItems an array of <li> elements?
listItems is an instance of the jQuery object which wraps an array of DOM elements. It isn't a regular array why is why we call get() on it to get back a plain array which we know can be reversed.
@tfmontague - Do you have performance benchmarks to prove that?
I disagree with that statement. If using .html() somehow turned out to be noticeably faster than reordering node elements and your application demands performance and this element reorder is a bottleneck, then by all means please go ahead and use html(). The reason I would prefer not to use html() is because of incorrectness. html() will recreate all those elements from scratch and any state that is not serialized such as event handlers will get lost. So it won't simply be a reorder operation anymore but a slightly more destructive operation with other side-effects.
|
78

Edit: Anurag's answer is better than mine.

ul = $('#my-ul'); // your parent ul element ul.children().each(function(i,li){ul.prepend(li)}) 

If you call .prepend() on an object containing more than one element, the element being appended will be cloned for the additional target elements after the first, so be sure you're only selecting a single element.

4 Comments

i dont think that would get rid of the listed elements though. So you would get a reverse list and the original list. Correct me if im wrong.
@Matt - a DOM element can only exist at one place, so in this case it is moved around, not copied.
in fact, you can copy and paste the code and try it on this page, and see the menu bar reverse itself.
One more clarification: if you call .prepend() on an object containing more than one element, the element being appended will be cloned for the additional target elements after the first. So $('.many-elements').prepend($('#unique-element') is going to create copies of the element with id #unique-element. The example above will do this, on a page with multiple ul elements, but this won't: uls = $('ul'); // all UL elements uls.each(function(i,ul){ $(ul).children().each(function(i,li){$(ul).prepend(li)}) })
5

Try this:

$(function() { $.fn.reverse = [].reverse; var x = $('li'); $('ul').empty().append(x.reverse()); }); 

2 Comments

You're creating an unused array with []. Wouldn't it be better to use Array.prototype.reverse instead of [].reverse?
The .empty is redundant - each element object only exists once and will be automatically removed from its original position in the DOM as its put back into its new position.
4

All the answer given before me are best but you can try this also

$('#btnrev').click(function(){ $('ul').html($('ul').find('li').get().reverse()); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> <button id="btnrev"> click </button>

Comments

1

oneliner:

$('ul').append($('ul>').detach().get().reverse()); 

1 Comment

This approach (the .get().reverse() moment) is also good if you only want to process elements in reverse order. Say, I have a list of entries, each contains a list of other entries. The template contains the container (list) and a template row, and to visualize template in development, I add a small code that populates the container with a few copies of the template row. So I grabbed both lists with selector, reversed, and first cloned rows in the inner list, then filled the list in the outer container. Nice and dandy, thanks for suggestion!
0

No Jquery Solution

Element.prototype.reverse = function(){ var c = [].slice.call(this.children).reverse(); while (this.firstChild) { this.removeChild(this.firstChild); }; c.forEach(function( child ){ this.appendChild(child) }.bind(this)) } 

And use like :

document.querySelector('ul').reverse(); // children are now reversed 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.