ngFor with index as value in attribute
Asked Answered
I

11

926

I have a simple ngFor loop which also keeps track of the current index. I want to store that index value in an attribute so I can print it. But I can't figure out how this works.

I basically have this:

<ul *ngFor="#item of items; #i = index" data-index="#i">
    <li>{{item}}</li>
</ul>

I want to store the value of #i in the attribute data-index. I tried several methods but none of them worked.

I have a demo here: http://plnkr.co/edit/EXpOKAEIFlI9QwuRcZqp?p=preview

How can I store the index value in the data-index attribute?

Incurvate answered 15/2, 2016 at 9:27 Comment(1)
Just a note - with the *ngFor on the UL as in this question, this would repeat the UL for each item, not the LIVerbify
F
1570

In Angular Version 17+ using built in control flow:

<ul>
  @for (item of items; track item; let  i = $index) {    
    <li>
        {{i+1}} {{item}}
    </li>
    }
</ul>

In Angular Version 5+:

<ul>
  <li *ngFor="let item of items; index as i">
    {{i+1}} {{item}}
  </li>
</ul>

I would use this syntax to set the index value into an attribute of the HTML element:

Angular 2-4

You have to use let to declare the value rather than #.

<ul>
    <li *ngFor="let item of items; let i = index" [attr.data-index]="i">
        {{item}}
    </li>
</ul>

AngularJS

<ul>
    <li *ngFor="#item of items; #i = index" [attr.data-index]="i">
        {{item}}
    </li>
</ul>

Here is the updated plunkr: http://plnkr.co/edit/LiCeyKGUapS5JKkRWnUJ?p=preview.

French answered 15/2, 2016 at 9:29 Comment(6)
Just for curiosity, why [attr['data-index']]=i would not work, where as it evaluate as sameFredrick
In fact, the attr. is a syntax to tell Angular2 to set the value of the expression to the attribute name. It's not just like evaluating JSON, I guess ;-) See this link: angular.io/docs/ts/latest/guide/template-syntax.htmlFrench
I rolled back the recent edit in order to have both the original answer and the new updated code value. I was searching for some early beta stuff and saw that this answer was modified, so it no longer applied to the beta version of angular 2.Sherysherye
UPDATE: 08/2017 <div *ngFor="let hero of heroes; let i=index; trackBy: trackById" >Zygophyllaceous
as of Oct 17, 2018 Angular 6 is using *ngFor="let item of items; index as i" See Leo's answer below.Erivan
Angular 1.x (known as AngularJS as opposed to Angular) doesn't use *nfFor structural directive at all. On the old version you would ng-repeat="item in items" and then access provided variables within the template as $index, $even, $odd... See the docs yourself.Matamoros
N
491

In Angular 5/6/7/8:

<ul>
  <li *ngFor="let item of items; index as i">
    {{i+1}} {{item}}
  </li>
</ul>

In older versions

<ul *ngFor="let item of items; let i = index">
  <li>{{i+1}} {{item}}</li>
</ul>

Angular.io ▸ API ▸ NgForOf

Unit test examples

Another interesting example

Neritic answered 4/12, 2017 at 14:29 Comment(2)
index as i works great, thank you. But isn't the *ngFor meant to go on the element to be repeated (e.g. the <li> in this case)? The code you suggested creates multiple <ul>s rathers than multiple <li>s.Heliotrope
index as i is more elegant than let i = indexNissensohn
G
126

Just an update to this, Thierry's answer is still correct, but there has been an update to Angular2 with regards to:

<ul *ngFor="let item of items; let i = index" [attr.data-index]="i">
  <li>{{item}}</li>
</ul>

The #i = index should now be let i = index

EDIT/UPDATE:

The *ngFor should be on the element you're wanting to foreach, so for this example it should be:

<ul>
  <li *ngFor="let item of items; let i = index" [attr.data-index]="i">{{item}}</li>
</ul>

EDIT/UPDATE

Angular 5

<ul>
  <li *ngFor="let item of items; index as i" [attr.data-index]="i">{{item}}</li>
</ul>

EDIIT/UPDATE

Angular 7/8

<ul *ngFor="let item of items; index as i">
  <li [attr.data-index]="i">{{item}}</li>
</ul>
Gripsack answered 28/6, 2016 at 9:23 Comment(2)
And #item should be let item ;-)Unalloyed
Just a note - with the *ngFor on the UL as in this answer (except the Angular 5 update), this would repeat the UL for each item, not the LIVerbify
D
55

I think its already been answered before, but just a correction if you are populating an unordered list, the *ngFor will come in the element which you want to repeat. So it should be insdide <li>. Also, Angular2 now uses let to declare a variable.

<ul>
    <li *ngFor="let item of items; let i = index" [attr.data-index]="i">     
               {{item}}
    </li>
</ul>
Dialectician answered 25/7, 2016 at 20:49 Comment(3)
I think that it is best practice to specify the *ngFor directive in ul tag <ul *ngFor="let item of items; index as i" [attr.data-index]="i"> <li > {{item}} </li> </ul>Bolden
If you specify ngFor in the ul tag, then the entity that will be repeated will be ul, but here u dont want to repeat the ul, you just want to iterate on the list elements i.e. li.Dialectician
@Dialectician is correct here, the *ngFor goes on the element to be repeated, so the original question as written would get a lot of UL elements, each with a single LI.Verbify
S
36

Adding this late answer to show a case most people will come across. If you only need to see what is the last item in the list, use the last key word:

<div *ngFor="let item of devcaseFeedback.reviewItems; let last = last">
  <divider *ngIf="!last"></divider>
</div>

This will add the divider component to every item except the last.

Because of the comment below, I will add the rest of the ngFor exported values that can be aliased to local variables (As are shown in the docs):

  • $implicit: T: The value of the individual items in the iterable (ngForOf).
  • ngForOf: NgIterable: The value of the iterable expression. Useful when the expression is more complex then a property access, for example when using the async pipe (userStreams | async).
  • index: number: The index of the current item in the iterable.
  • count: number: The length of the iterable.
  • first: boolean: True when the item is the first item in the iterable.
  • last: boolean: True when the item is the last item in the iterable.
  • even: boolean: True when the item has an even index in the iterable.
  • odd: boolean: True when the item has an odd index in the iterable.
Seward answered 20/10, 2020 at 8:13 Comment(4)
How do you know this? Is there some kind of documentation somewhere, or a typescript file, or something that lists all the keywords we can use?Map
Damn. I was hoping to find a similar list for Angular Material's tables by browsing through the .ts files, or something. The documentation for Material Tables is a lot, lot worse.Map
It is in common.d.ts in angular/common thats where ngFor comes fromSeward
Link to docs: angular.io/api/common/NgForOf#local-variablesVerbify
K
23

The other answers are correct but you can omit the [attr.data-index] altogether and just use

<ul>
    <li *ngFor="let item of items; let i = index">{{i + 1}}</li>
</ul
Kwasi answered 10/11, 2017 at 20:59 Comment(0)
S
9

You can use [attr.data-index] directly to save the index to data-index attribute which is available in Angular versions 2 and above.

    <ul*ngFor="let item of items; let i = index" [attr.data-index]="i">
         <li>{{item}}</li>
    </ul>
Selfreliance answered 27/12, 2019 at 9:20 Comment(0)
D
9

with laravel pagination

file.component.ts file

    datasource: any = {
        data: []
    }

    loadData() {
        this.service.find(this.params).subscribe((res: any) => {
            this.datasource = res;
        });
    }

html file

   <tr *ngFor="let item of datasource.data; let i = index">
       <th>{{ datasource.from + i }}</th>
   </tr>
Declamation answered 16/5, 2020 at 18:55 Comment(0)
H
2

Try this

<div *ngFor="let piece of allPieces; let i=index">
{{i}} // this will give index
</div>
Hastings answered 15/4, 2019 at 11:0 Comment(0)
P
2

In Angular 17+

You can use the new syntax:

@for (item of items; track item.id; let idx = $index) {
  {{idx}} - {{item}}
}
Propitiatory answered 14/12, 2023 at 11:22 Comment(0)
C
-1

Get API call

    @Injectable({
      providedIn: 'root',
    })
    export class ApiService {

      private readonly postsSubject = new BehaviorSubject<any>(null);
      readonly postsResult$ = this.postsSubject.asObservable();

      get postsResult(): any {
        return this.postsSubject.getValue();
      }
      set postsResult(posts: any) {
        this.postsSubject.next(gifRes);
      }
    
      constructor(private http: HttpClient) {}
        getSearchResult(): Observable<any> {
            this.postsResult = this.http.get<any>('https://jsonplaceholder.typicode.com/posts');
          }
}

For getting index of postResult

<div *ngFor="let post of apiService.postsResult$ | async; let i = index">
{{i}} - {{post.title}}
<div>
Conah answered 8/12, 2022 at 16:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.