Angular: local variables of *ngFor directive

When you become an adept of Angular development then *ngFor becomes probably the most used tool in your work with templates, of-course alongside with *ngIf.

Quite simple, it allows you to iterate over any collection. A standard example of displaying a list of data from component would look like:

@Component({ 
selector: 'app-product-list',
template: `
<ul>
<li *ngFor="let product of bankProducts">
<p> {{ product }} </p>
</li>
</ul>
`,
})
export class ProductList {
bankProducts: string[] = ['cards', 'deposits', 'loans'];
}

Usually, when we work with *ngFor directive, we associate it with this functionality. In some cases we remember that it also has index variable. And that’s all. But did you know, that there is a whole bundle of additional services, that we can use to improve our business login in template iteration? Believe me, there are!

However before going further, let’s clarify one moment, that’ll help avoid confusion in terminology: originally in Angular’s documentation, we often see the notice of ngForOf directive.

How it differs from *ngFor? Long story short — it doesn’t! It’s just a shortcut for ngForOf directive. The asterisk basically is a “syntactic sugar” that hides transformation of the *ngIf attribute into a <ng-template> element, wrapped around the host element

So, when you see mentioning of both: ngForOf and *ngFor , just know — they are the same.

ngFor local variables:

Ok, so with *ngFor you have a possibility to iterate over collection. But what if you want to apply some logic, that is required not on every item in the list? Some logic, based on items order, or its position in the collection?

From official documentation:

Explanation in human words:

Angular team has decided to provide us with some additional tooling during iteration. They have reserved a couple of words in templates and you can access their value by creation of local template variables.

These local variables are listed below, but the most commonly used are index, count, first, last, even, odd.

  • 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.
  • $implicit: T: The value of the individual items in the iterable (ngForOf).
  • ngForOf: NgIterable<T>: 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).

These variables will be accessible only locally — inside current tag and its children, where *ngFor is declared. Thus where the name comes from — local variables.

Usage syntax:

There are just 2 rules to remember:

  1. They are always used inside *ngFor loop expression;
  2. You need to initialise a separate variable, that will be automatically assigned with the value.
<li *ngFor="let product of bankProducts; let i = index">
<p> {{i}}: {{ product }} </p>
</li>

Here i — is the locally introduced variable, that you assign with value from its index

Another syntax for local variables — is to use aliases:

<li *ngFor="let product of bankProducts; index as i">
<p>{{i}}: {{ product }} </p>
</li>

It means that 2 expressions below are exactly the same:

let f = first// is the same as:first as f

It’s fully the matter of choice what syntax to choose. I, for example, prefer to use aliases, because it looks in the same manner as I would do it with async pipe alias:

<li *ngFor="let p of bankProducts$ as product">
<p> {{ product }} </p>
</li>

Real-life examples:

These local variables become very useful in such tasks, as described below. I intentionally use both: aliases and explicit variables declaration for different syntax demonstration.

  1. To add different css classes, based on odd-even order
<div *ngFor="let product of products; 
let isOdd=odd;
let isEven=even"

[class.odd]="isOdd"
[class.even]="isEven" >
<p>{{product.name}}</p>
</div>

2. To separate items with comma, but not to add it to the last one:

<div *ngFor="let product of productsArray; 
let isLast=last; >
{{ product }}{{ isLast ? '' : ', ' }}
</div>

3. The first button in the group has to be selected:

<mat-button-toggle-group 
name="productName"
aria-label="Product Name>
<mat-button-toggle *ngFor="let product of productsArray;
first as isFirst;"
[value]="product.name"
[checked]="isFirst">
{{product.name}}
</mat-button-toggle>
</mat-button-toggle-group>

Conclusion

Since the main goal of any UI framework is to display data from backend on the user’s screen, hence the convenience of items iteration — is one of the major requirements for the framework.

Angular provides us with *ngFor directive, that comes alongside with its local variables. With their help, the applying of business logic during data iteration becomes an easy job way with a pretty looking syntax.

Share with your friends! Clap 👏 as max as 50 times.

Senior Front-End developer in Backbase, Amsterdam