Jack Mills
Jack Mills

Reputation: 6132

JQuery .each() backwards

I'm using JQuery to select some elements on a page and then move them around in the DOM. The problem I'm having is I need to select all the elements in the reverse order that JQuery naturally wants to select them. For example:

<ul>
   <li>Item 1</li>
   <li>Item 2</li>
   <li>Item 3</li>
   <li>Item 4</li>
   <li>Item 5</li>
</ul>

I want to select all the li items and use the .each() command on them but I want to start with Item 5, then Item 4 etc. Is this possible?

Upvotes: 481

Views: 234541

Answers (12)

Ramin Bateni
Ramin Bateni

Reputation: 17415

This answer is like JoeChung's answer with the difference that by this code you can just use the container element (ul):

$($("ul").children().get().reverse()).each(function(i, elm) {

    console.log($(elm).text()) 

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
   <li>Item 1</li>
   <li>Item 2</li>
   <li>Item 3</li>
   <li>Item 4</li>
   <li>Item 5</li>
</ul>

Upvotes: 0

mattyfew
mattyfew

Reputation: 163

You can also try

var arr = [].reverse.call($('li'))
arr.each(function(){ ... })

Upvotes: -1

yurakis
yurakis

Reputation: 331

If you don't want to save method into jQuery.fn you can use

[].reverse.call($('li'));

Upvotes: 9

NRTRX
NRTRX

Reputation: 161

I found Array.prototype.reverse unsuccessful with objects, so I made a new jQuery function to use as an alternative: jQuery.eachBack(). It iterates through as the normal jQuery.each() would, and stores each key into an array. It then reverses that array and performs the callback on the original array/object in the order of the reversed keys.

jQuery.eachBack=function (obj, callback) {
    var revKeys=[]; $.each(obj,function(rind,rval){revKeys.push(rind);}); 
    revKeys.reverse();
    $.each(revKeys,function (kind,i){
        if(callback.call(obj[i], i, obj[i]) === false) {    return false;}
    });
    return obj;
}   
jQuery.fn.eachBack=function (callback,args) {
    return jQuery.eachBack(this, callback, args);
}

Upvotes: 2

Sergio
Sergio

Reputation: 28837

Here are different options for this:

First: without jQuery:

var lis = document.querySelectorAll('ul > li');
var contents = [].map.call(lis, function (li) {
    return li.innerHTML;
}).reverse().forEach(function (content, i) {
    lis[i].innerHTML = content;
});

Demo here

... and with jQuery:

You can use this:

$($("ul > li").get().reverse()).each(function (i) {
    $(this).text( 'Item ' + (++i));
});

Demo here

Another way, using also jQuery with reverse is:

$.fn.reverse = [].reverse;
$("ul > li").reverse().each(function (i) {
    $(this).text( 'Item ' + (++i));
});

This demo here.

One more alternative is to use the length (count of elements matching that selector) and go down from there using the index of each iteration. Then you can use this:

var $li = $("ul > li");
$li.each(function (i) {
    $(this).text( 'Item ' + ($li.length - i));
});

This demo here

One more, kind of related to the one above:

var $li = $("ul > li");
$li.text(function (i) {
    return 'Item ' + ($li.length - i);
});

Demo here

Upvotes: 25

Jimmy M
Jimmy M

Reputation: 25

I think u need

.parentsUntill()

Upvotes: -2

James Westgate
James Westgate

Reputation: 11444

I prefer creating a reverse plug-in eg

jQuery.fn.reverse = function(fn) {       
   var i = this.length;

   while(i--) {
       fn.call(this[i], i, this[i])
   }
};

Usage eg:

$('#product-panel > div').reverse(function(i, e) {
    alert(i);
    alert(e);
});

Upvotes: 14

Waldo Hampton
Waldo Hampton

Reputation: 4480

I present you with the cleanest way ever, in the form of the world's smallest jquery plugin:

jQuery.fn.reverse = [].reverse;

Usage:

$('jquery-selectors-go-here').reverse().each(function () {
    //business as usual goes here
});

-All credit to Michael Geary in his post here: http://www.mail-archive.com/[email protected]/msg04261.html

Upvotes: 431

finklez
finklez

Reputation: 59

Needed to do a reverse on $.each so i used Vinay idea:

//jQuery.each(collection, callback) =>
$.each($(collection).get().reverse(), callback func() {});

worked nicely, thanks

Upvotes: 5

Vinay Sajip
Vinay Sajip

Reputation: 99317

You can do

jQuery.fn.reverse = function() {
    return this.pushStack(this.get().reverse(), arguments);
}; 

followed by

$(selector).reverse().each(...) 

Upvotes: 65

Joe Chung
Joe Chung

Reputation: 12123

$($("li").get().reverse()).each(function() { /* ... */ });

Upvotes: 733

David Andres
David Andres

Reputation: 31781

You cannot iterate backwards with the jQuery each function, but you can still leverage jQuery syntax.

Try the following:

//get an array of the matching DOM elements   
var liItems = $("ul#myUL li").get();

//iterate through this array in reverse order    
for(var i = liItems.length - 1; i >= 0; --i)
{
  //do Something
}

Upvotes: 4

Related Questions