angular ng-repeat in reverse
Asked Answered
F

17

231

How can i get a reversed array in angular? i'm trying to use orderBy filter, but it needs a predicate(e.g. 'name') to sort:

<tr ng-repeat="friend in friends | orderBy:'name':true">
      <td>{{friend.name}}</td>
      <td>{{friend.phone}}</td>
      <td>{{friend.age}}</td>
<tr>

Is there a way to reverse original array, without sorting. like that:

<tr ng-repeat="friend in friends | orderBy:'':true">
      <td>{{friend.name}}</td>
      <td>{{friend.phone}}</td>
      <td>{{friend.age}}</td>
<tr>
Flyaway answered 7/3, 2013 at 8:48 Comment(5)
This is the new and right way https://mcmap.net/q/119826/-descending-order-by-date-filter-in-angularjsEndometriosis
@QuiteNothing That is the right way if you want to reverse an array with an expression. In this case, the question was how to revere an array without one.Tarah
<tr ng-repeat="friend in friends | orderBy:'-name'">Buckles
See my answer below for the simple 1 line and correct solution. There's no need to make any methods. I wonder why people are making additional methods for this.Ranson
Always use filters for changing the ng-repeat behavior! @Trevor Senior did a good job.Theretofore
T
333

I would suggest using a custom filter such as this:

app.filter('reverse', function() {
  return function(items) {
    return items.slice().reverse();
  };
});

Which can then be used like:

<div ng-repeat="friend in friends | reverse">{{friend.name}}</div>

See it working here: Plunker Demonstration


This filter can be customized to fit your needs as seen fit. I have provided other examples in the demonstration. Some options include checking that the variable is an array before performing the reverse, or making it more lenient to allow the reversal of more things such as strings.

Tarah answered 7/3, 2013 at 9:42 Comment(9)
Nice! Just be aware that items.reverse() modifies the array instead of just creating a new one and returning it.Lunsford
Thanks! I had overlooked that. I threw in a slice() to solve that problem.Tarah
You should add if (!angular.isArray(items)) return false; to verify that you have an array before trying to reverse it.Ezarras
Need to be more defensive against null, should use the following instead: return items ? items.slice().reverse() : [];Lamella
@Chris Yeung: Not advisable to return empty "[]" when null. Better to return the original value.Hom
If you do not want to modify the array - use this solution https://mcmap.net/q/117370/-angular-ng-repeat-in-reverseTharpe
Had to include if (!items) { return }; before the return to stop stop console errors firing on sliceEuphrasy
Nice, people need to start using filters, Thanks <3Theretofore
app.filter('reverse', function() { return function(items) { return items.reverse(); }); It also return sameNix
R
208

This is what i used:

<alert ng-repeat="alert in alerts.slice().reverse()" type="alert.type" close="alerts.splice(index, 1)">{{$index + 1}}: {{alert.msg}}</alert>

Update:

My answer was OK for old version of Angular. Now, you should be using

ng-repeat="friend in friends | orderBy:'-'"

or

ng-repeat="friend in friends | orderBy:'+':true"

from https://mcmap.net/q/117370/-angular-ng-repeat-in-reverse

Rodmur answered 12/4, 2014 at 13:23 Comment(2)
Uing track by, this the only way that worked for meHyponasty
@delboud you should be using track by after orderBy: ng-repeat="friend in friends | orderBy:'+': true track by $index"Transcendentalistic
T
124

Sorry for bringing this up after a year, but there is an new, easier solution, which works for Angular v1.3.0-rc.5 and later.

It is mentioned in the docs: "If no property is provided, (e.g. '+') then the array element itself is used to compare where sorting". So, the solution will be:

ng-repeat="friend in friends | orderBy:'-'" or

ng-repeat="friend in friends | orderBy:'+':true"

This solution seems to be better because it does not modify an array and does not require additional computational resources (at least in our code). I've read all existing answers and still prefer this one to them.

Tharpe answered 29/10, 2014 at 16:26 Comment(9)
Thanks for the tip! As a heads up for anyone else reading this, looks like this doesn't work in rc4 (v1.3.0-rc.4). If anyone gets a chance to try it in the new release, let us know!Pronouncement
@Pronouncement Thanks for the comment! According to the same documentation it should work starting from the v1.3.0-rc.5 (rc.5 docs vs rc.4 docs). I have updated the answerTharpe
I have used 1.3.4 version personally - it worked perfectly there.Tharpe
Not working for me (v1.3.5). Tried orderBy:'+':true, orderBy:'-':true, orderBy:'-':false, orderBy:'+':false :(V
@V Sorry for the late answer. Here you go - a working example with angular v1.3.5 jsfiddle.net/dmitry_gonchar/L98foxhm/1. Probably the problem was in another place.Tharpe
Dmitry, thx for the Fiddle -- I'll have to investigate further why my code was having issues. Thx for all your input!V
Dmitry, something is still wrong in your jsfiddle. Now, when I use orderBy:'+':false or even | orderBy:'+', I still got a reverse order.Root
@Root True. But it works if you specify the field ('+id', '-id' f.e.). Maybe this is a bug in Angular, that it does not work with normal order if you do not specify a field? I took this method from the docs (link is in the answer), so I was surprised as well as you. Anyway, the question was how to reverse an array.Tharpe
The fiddle doesn't work anymore, also doesnt work in 1.4.0Roderica
R
57

Simple solution:- (no need to make any methods)

ng-repeat = "friend in friends | orderBy: reverse:true"
Ranson answered 3/10, 2016 at 9:4 Comment(1)
Works just fine for me. Thanks!Agio
D
55

You can reverse by the $index parameter

<tr ng-repeat="friend in friends | orderBy:'$index':true">
Derzon answered 22/9, 2013 at 18:1 Comment(3)
Should work, but doesn't (tried with and without quotes around $index). I'm on Angular 1.1.5.Billowy
Worked for me (were using a property for sorting instead of $index though) #16261848Chevron
Does not work with AngularJS 1.2.13. I modified my array of objects to add an id to each object. The id being the index of the object inside the array. Then ng-repeat="friend in friends | orderBy:'id':true" works.Cucullate
L
17

You can just call a method on your scope to reverse it for you, like this:

<!doctype html>
<html ng-app="myApp">
<head>
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
    <script>
    angular.module('myApp', []).controller('Ctrl', function($scope) {
        $scope.items = [1, 2, 3, 4];
        $scope.reverse = function(array) {
            var copy = [].concat(array);
            return copy.reverse();
        }
    });
    </script>
</head>
<body ng-controller="Ctrl">
    <ul>
        <li ng-repeat="item in items">{{item}}</li>
    </ul>
    <ul>
        <li ng-repeat="item in reverse(items)">{{item}}</li>
    </ul>
</body>
</html>

Note that the $scope.reverse creates a copy of the array since Array.prototype.reverse modifies the original array.

Lunsford answered 7/3, 2013 at 9:10 Comment(0)
T
13

if you are using 1.3.x, you can use the following

{{ orderBy_expression | orderBy : expression : reverse}}

Example List books by published date in descending order

<div ng-repeat="book in books|orderBy:'publishedDate':true">

source:https://docs.angularjs.org/api/ng/filter/orderBy

Thadeus answered 7/5, 2015 at 10:11 Comment(0)
A
11

If you are using angularjs version 1.4.4 and above,an easy way to sort is using the "$index".

 <ul>
  <li ng-repeat="friend in friends|orderBy:$index:true">{{friend.name}}</li>
</ul>

view demo

Alphorn answered 2/6, 2016 at 13:36 Comment(0)
L
1

When using MVC in .NET with Angular you can always use OrderByDecending() when doing your db query like this:

var reversedList = dbContext.GetAll().OrderByDecending(x => x.Id).ToList();

Then on the Angular side, it will already be reversed in some browsers (IE). When supporting Chrome and FF, you would then need to add orderBy:

<tr ng-repeat="item in items | orderBy:'-Id'">

In this example, you'd be sorting in descending order on the .Id property. If you're using paging, this gets more complicated because only the first page would be sorted. You'd need to handle this via a .js filter file for your controller, or in some other way.

Lennalennard answered 14/2, 2017 at 0:42 Comment(0)
M
0

You can also use .reverse(). It's a native array function

<div ng-repeat="friend in friends.reverse()">{{friend.name}}</div>

Middlesworth answered 14/8, 2015 at 12:31 Comment(2)
Your down-vote can only mean one thing: you have more incoming data. If the {} or [] keeps receiving data, it'll reverse each time, obviously. It's a new digestMiddlesworth
Warning for whoever wants to use this: reverse reverses the array in place, it does not just return a reversed copy. This means that every time this is evaluated, the array will be reversed.Erv
H
0

That's because you are using JSON Object. When you face such problems then change your JSON Object to JSON Array Object.

For Example,

{"India":"IN","America":"US","United Kingdon":"UK"} json object
[{"country":"India","countryId":"IN"},{"country":"America","countryId":"US"},{"country":"United Kingdon","countryId":"UK"}] 
Halliday answered 6/2, 2016 at 8:23 Comment(0)
K
0

The orderBy filter performs a stable sorting as of Angular 1.4.5. (See the GitHub pull request https://github.com/angular/angular.js/pull/12408.)

So it is sufficient to use a constant predicate and reverse set to true:

<div ng-repeat="friend in friends | orderBy:0:true">{{friend.name}}</div>
Kwangju answered 14/2, 2016 at 20:12 Comment(0)
H
0

I found something like this, but instead of array i use objects.

Here is my solution for objects:

Add custom filter:

app.filter('orderObjectBy', function() {
    return function(items, field, reverse){

        var strRef = function (object, reference) {
            function arr_deref(o, ref, i) {
                return !ref ? o : (o[ref.slice(0, i ? -1 : ref.length)]);
            }
            function dot_deref(o, ref) {
                return !ref ? o : ref.split('[').reduce(arr_deref, o);
            }
            return reference.split('.').reduce(dot_deref, object);
        };

        var filtered = [];

        angular.forEach(items, function(item) {
           filtered.push(item);
        });
        filtered.sort(function (a, b) {
           return (strRef(a, field) > strRef(a, field) ? 1 : -1);
        });
        if(reverse) filtered.reverse();
        return filtered;
    };
});

Which can then be used like

<div ng-repeat="(key, value) in items | orderObjectBy:'field.any.deep':true">

If you need old browser support, you will need to define the reduce function (this is only available in ECMA-262 mozilla.org)

// Production steps of ECMA-262, Edition 5, 15.4.4.21
// Reference: http://es5.github.io/#x15.4.4.21
if (!Array.prototype.reduce) {
Array.prototype.reduce = function(callback /*, initialValue*/) {
'use strict';
  if (this == null) {
    throw new TypeError('Array.prototype.reduce called on null or undefined');
  }
  if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function');
  }
  var t = Object(this), len = t.length >>> 0, k = 0, value;
  if (arguments.length == 2) {
    value = arguments[1];
  } else {
    while (k < len && !(k in t)) {
      k++; 
    }
    if (k >= len) {
      throw new TypeError('Reduce of empty array with no initial value');
    }
    value = t[k++];
  }
  for (; k < len; k++) {
    if (k in t) {
      value = callback(value, t[k], k, t);
    }
  }
  return value;
};
}
Henning answered 26/4, 2016 at 14:5 Comment(0)
H
0

I had gotten frustrated with this problem myself and so I modified the filter that was created by @Trevor Senior as I was running into an issue with my console saying that it could not use the reverse method. I also, wanted to keep the integrity of the object because this is what Angular is originally using in a ng-repeat directive. In this case I used the input of stupid (key) because the console will get upset saying there are duplicates and in my case I needed to track by $index.

Filter:

angular.module('main').filter('reverse', function() {
    return function(stupid, items) {
    var itemss = items.files;
    itemss = itemss.reverse();  
    return items.files = itemss; 
  };
});

HTML: <div ng-repeat="items in items track by $index | reverse: items">

Horsecar answered 12/8, 2016 at 14:49 Comment(0)
S
0

Im adding one answer that no one mentioned. I would try to make the server do it if you have one. Clientside filtering can be dangerous if the server returns a lot of records. Because you might be forced to add paging. If you have paging from the server then the client filter on order, would be in the current page. Which would confuse the end user. So if you have a server, then send the orderby with the call and let the server return it.

Shirtwaist answered 17/1, 2017 at 10:23 Comment(0)
K
0

Useful tip:

You can reverse you're array with vanilla Js: yourarray .reverse()

Caution: reverse is destructive, so it will change youre array, not only the variable.

Kacykaczer answered 12/11, 2018 at 20:37 Comment(0)
L
-2

I would sugest using array native reverse method is always better choice over creating filter or using $index.

<div ng-repeat="friend in friends.reverse()">{{friend.name}}</div>

Plnkr_demo.

Lederhosen answered 14/9, 2015 at 13:40 Comment(1)
You are reversing the original array...A better practice would be to return a new array that is reversed.Schmooze

© 2022 - 2024 — McMap. All rights reserved.