13

Trying to learn something about filtering and ordering in Angular 2. I can't seem to find any decent resources and I'm stuck at how to order an ngFor output in reverse order using the index. I have written the the following pipe put it keeps giving me errors that array slice in not a function.

@Pipe({
    name: 'reverse'
})
export class ReversePipe implements PipeTransform {
    transform(arr) {
        var copy = arr.slice();
        return copy.reverse();
    }
}

and my ngfor looks like this.

<div class="table-row generic" *ngFor="let advert of activeAdverts | reverse let i = index;" [attr.data-index]="i" (click)="viewAd(advert.title)">      
    <div class="table-cell white-text">{{ i+1 }}</div>                    
    <div class="table-cell white-text">{{advert.title}}</div>
    <div class="table-cell green-text">{{advert.advert}}</div>
</div>
Shadow
  • 8,749
  • 4
  • 47
  • 57
Hamburgersn Heroin
  • 207
  • 1
  • 2
  • 12

8 Answers8

13

I would add .slice() as well

*ngFor="let advert of activeAdverts.slice().reverse() let i = index;"
msanford
  • 11,803
  • 11
  • 66
  • 93
Chris Skura
  • 161
  • 1
  • 3
  • 1
    Why to use slice() here? And if we will not do slice() what will happen? – Satish Patro Feb 11 '19 at 05:22
  • 2
    Reverse() works in place. It means, it will change the original array. Slice without parameters returns a copy of activeAdverts, so original array, in this case, stays unchanged. – Prokhor Sednev Apr 26 '19 at 12:39
12

For such common use cases, I would suggest you to use reverse pipe from ng-pipes module: https://github.com/danrevah/ng-pipes#reverse-1

From the DOCS:

in the controller:

this.items = [1, 2, 3];

in the view:

<li *ngFor="let item of items | reverse"> <!-- Array: [3, 2, 1] -->
D_R
  • 4,894
  • 4
  • 45
  • 62
7

I think @BhaskerYadav gave the best answer. Changing the original array is a bad idea and his/her idea has no side-effects, performance or otherwise. IMHO it just needs a slight improvement as all that index dereferencing is unreadable at scale.

<tr *ngFor="let _ of activeAdverts; let i = index">
  <ng-container *ngIf="activeAdverts[activeAdverts.length-i-1] as advert">
    <td>{{advert.p}}</td>
    <td>{{advert.q}}</td>
    ...
  </ng-container>
</tr>
Mark Florence
  • 363
  • 4
  • 8
  • This worked for me. But, didn't understand what you mean by "index dereferencing is unreadable at scale". Could you please help explain. Thanks. – User3250 Aug 07 '18 at 16:07
  • Sure thing. All the examples show just a couple of table cells. But that isn't realistic. What if there were 10, 20? If you had to write `activeAdverts[activeAdverts.length-i-1]` in each, your template would rapidly become unreadable. The `as` keyword of `*ngIf` is underused but great for creating a local variable -- and assigning it with the `*ngIf` expression. So in my example, you only need write the lengthy index dereference once. – Mark Florence Aug 08 '18 at 18:46
  • Ahh! Got you. Thanks a ton! :) – User3250 Aug 09 '18 at 01:38
  • @MarkFlorence what if then I dynamically push activeAdverts? – Chirag Jan 16 '19 at 06:43
4

Using the following method u can reverse the output, but orignal array won't be modified,

 <tr *ngFor="let advert of activeAdverts; let i = index" >
           <td>{{activeAdverts[activeAdverts.length-i-1]}}</td>
  </tr>
BhaskerYadav
  • 569
  • 3
  • 24
3

Use this

*ngFor="let item of items.slice().reverse()"
matthias_h
  • 11,356
  • 9
  • 22
  • 40
Trilok Singh
  • 1,227
  • 12
  • 10
2

The most simple way I was able to make it work is to just use activeAdverts.reverse(). In your case:

<div class="table-row generic" *ngFor="let advert of activeAdverts.reverse() let i = index;" [attr.data-index]="i" (click)="viewAd(advert.title)">      
    <div class="table-cell white-text">{{ i+1 }}</div>                    
    <div class="table-cell white-text">{{advert.title}}</div>
    <div class="table-cell green-text">{{advert.advert}}</div>
</div>

I found this answer to do the trick

Pini Cheyni
  • 5,073
  • 2
  • 40
  • 58
0

Lodash reverse worked for me.

import { reverse} from "lodash";

this.cloudMessages = reverse(this.cloudMessages)
Sampath
  • 63,341
  • 64
  • 307
  • 441
0

Use the default Angular Reverse method on ngFor

<div class="table-row generic" *ngFor="*ngFor="let advert of activeAdverts.slice().reverse() let i = index;" [attr.data-index]="i" (click)="viewAd(advert.title)">     
    <div class="table-cell white-text">{{ i+1 }}</div>                    
    <div class="table-cell white-text">{{advert.title}}</div>
    <div class="table-cell green-text">{{advert.advert}}</div>
</div>
Surya R Praveen
  • 3,393
  • 1
  • 24
  • 25