Search code examples
angularngforangular-ng-if

Declaring a counting variable in angular2 template ngFor


Suppose I have an array of data as follows.

datas : [
  {
    nums : [121,222,124,422,521,6312,7141,812]
  },{
    nums : [121,222,124,422,521,6312,7141,812]
  },{
    nums : [121,222,124,422,521,6312,7141,812]
  }
]
nums = [121,222,124,422,521,6312,7141,812]

I wanted to display the even numbers in the array after a serial number like shown below.

1. 222
2. 124
3. 422
4. 6312
5. 812
6. 222
7. 124
8. 422
9. 6312
10. 812
11. 222
12. 124
13. 422
14. 6312
15. 812

But I could not figure out a way to set the indexes after the "even" check. Currently, I display the texts using the following code.

<div *ngFor="let data of datas">
  <div *ngFor="let num of data.nums; let rowIndex = index">
    <div *ngIf="num % 2 == 0">
      {{rowIndex+1}}. {{num}}
    </div>
  </div>
</div>

But it displays

2. 222
3. 124
4. 422
6. 6312
8. 812
2. 222
3. 124
4. 422
6. 6312
8. 812
2. 222
3. 124
4. 422
6. 6312
8. 812

Is there a way to set a counter that increments every time the ngIf condition is validated so that I can display with the correct indexes.


Solution

  • You should use a pipe to filter the *ngFor. See https://angular.io/docs/ts/latest/guide/pipes.html ("Flying Heroes pipe") which gives a good example for that.

    <div *ngFor="let num of (nums | evenNums); let rowIndex=index">
      {{rowIndex+1}}. {{num}}
    </div>
    

    and

    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({ name: 'evenNums' })
    export class EvenNumsPipe implements PipeTransform {
      transform(allNums: number[]) {
        return allNums.filter(num => num % 2 == 0);
      }
    }
    

    Also compare How to apply filters to *ngFor

    Update: As far as I understand all you'd have to do is

    <div *ngFor="let data of datas">
      <div *ngFor="let num of (data.nums | evenNums); let rowIndex = index">
          {{rowIndex+1}}. {{num}}
      </div>
    </div>
    

    The pipe should just filter the nums the same way, doesn't matter if it's inside a nested for or whatever.

    Update 2: I have created a Plunkr to do this: https://plnkr.co/edit/NwoDPZqukKM7RyCHJudu?p=preview Seems like there is no other way than having a custom function that counts the rows so far. Angular does not support having a custom increment on a counter. I guess this is due to the guideline that there should be as minimal logic as possible in the templates.