Introduction
<div *ngFor="let leaf of ['π', 'ππ', 'πππ']; let i = index;">
<p>{{i + 1}}. {{leaf}}</p>
</div>
1. π
2. ππ
3. πππ
If you've worked with Angular, I'm sure you've come across this *ngFor
syntax at least once: let leaf of ['π', 'ππ', 'πππ']; let i = index;"
. However, have you ever wondered?
- Is there any alternative
*ngFor
syntax? - Where does the
index
variable come from? - How does the
leaf
variable iterate over and reference items of['π', 'ππ', 'πππ']
? - Why is it
let ... of ...
? Can we change it tolet ... something ...
?
What do you think about trying the following syntaxes with
*ngFor
?
1. let leaf of ['π±', 'π', 'πΏ']; let i = index;
2. let leaf; let i = index; of ['π±', 'π', 'πΏ'];
3. let i = index; let leaf; of ['π±', 'π', 'πΏ'];
4. let i = index let leaf; of: ['π±', 'π', 'πΏ'];
5. let i = index; of ['π±', 'π', 'πΏ']; let leaf;
6. let i = index; of: ['π±', 'π', 'πΏ'] let leaf;
7. 'Magic πͺ'; let i = index; of: ['π±', 'π', 'πΏ']; let leaf;
8. let leaf = $implicit of ['π±', 'π', 'πΏ']; let i = index;
9. let leaf = $implicit; let i = index; of ['π±', 'π', 'πΏ'];
10. let leaf = $implicit, let i = index, of ['π±', 'π', 'πΏ'];
You can quickly find the answer via this StackBlitz link.
Surprisingly, these peculiar syntaxes
compile without any errors. π€
How does this happen? What are the rules behind these syntax variations?
Demystifying *ngFor syntax
At first glance, you might be under the impression that you're required to use a semicolon
to delimit the calls and adhere to a certain order
, or that there might be more rules
you don't yet understand about how to use the syntax. But that's not the case - the syntax is actually quite flexible more than that.
Angular's microsyntax has 4 building blocks, that when combined in a particular way, make up the entire microsyntax API. These building blocks are:
- Expressions
- The
as
keyword - Keyed expressions
-
let
bindings
1. Expressions
Anything that, when referenced, returns a value.
- Raw value
<p *hello="'π Hey there'"></p>
- Calling a function
<p *hello="greeting()"></p>
- Referenced a variable
<p *ngIf="shouldDisplay"></p>
- Operator (
9 * 9
)
2. The
as
keyword
The rules behind the as
keyword as an alternative to let
. The most commonly used is combining between *ngIf
and AsyncPipe
.
<div *ngIf="(myFutureGirl$ | async) as myFutureGirl">
{{myFutureGirl}}
<div>
Oops, 404 π€¦ββοΈ
3.
keyExp
- Key Expressions
A key expression is simply an expression that you're able to bind to an input on a structural directive.
For example, the *ngFor
directive includes an ngForOf
input as follows:
/**
* The value of the iterable expression, which can be used as a
* [template input variable](guide/structural-directives#shorthand).
*/
@Input()
set ngForOf(ngForOf: U&NgIterable<T>|undefined|null) {
this._ngForOf = ngForOf;
this._ngForOfDirty = true;
}
In this case, the key expression is the of
keyword. This directly answers the question, Why is it let ... of ...
?
4.
let
bindings
The let
binding is used for reference the Template Context
. Let's take a look at our example:
let leaf of ['π±', 'π', 'πΏ']; let i = index;
There are two types of references
made using let
bindings:
- Implicit
In this case, the assigned expression on the right side is omitted, and it is equivalent to the following:
let leaf = $implicit
Angular automatically assigns the reference with the $implicit
key in the context.
- Explicit
let i = index
When we use let i = index
, it is clear that the variable i
references the index
key in the context.
Combining Things Together
- It starts with the * reserved token. It is an Angular special syntax companion with the Angular Structural Directive.
- Then, you have to declare the
selector
value of the directive itself. - Finally, you can bind to the
selector
as with any other input using the=
token.
The contents of the input itself are where the microsyntax goes.
1. First Item
Either an expression
or a let
binding.
If an expression
is passed, the value of the expression will be passed to the same input name as the selector
itself.
Let's take a look at *ngIf
implementation:
@Directive({
selector: '[ngIf]',
standalone: true,
})
export class NgIf<T = unknown> {
/**
* The Boolean expression to evaluate as the condition for showing a template.
*/
@Input()
set ngIf(condition: T) {
this._context.$implicit = this._context.ngIf = condition;
this._updateView();
}
}
*ngIf
includes an ngIf
input that is the same as the [ngIf]
selector itself.
If a let
binding is the first item, it will work exactly as it's explained in the previous section.
<!-- β
These ARE valid for the first item -->
<p *ngIf="'Expression'"></p>
<p *ngFor="let i = index; ..."></p>
<!-- π But these are NOT valid for the first item -->
<p *ngFor="of: ['π±', 'π', 'πΏ']; ..."></p>
<p *ngFor="index as i"></p>
2. Second Item and Beyond
After the first item, youβre able to pass in a let binding, an as binding, or a key expression.
Let's revisit these *ngFor
syntaxes at the very beginning of this post:
1. let leaf of ['π±', 'π', 'πΏ']; let i = index;
2. let leaf; let i = index; of ['π±', 'π', 'πΏ'];
3. let i = index; let leaf; of ['π±', 'π', 'πΏ'];
4. let i = index let leaf; of: ['π±', 'π', 'πΏ'];
5. let i = index; of ['π±', 'π', 'πΏ']; let leaf;
6. let i = index; of: ['π±', 'π', 'πΏ'] let leaf;
7. 'Magic πͺ'; let i = index; of: ['π±', 'π', 'πΏ']; let leaf;
8. let leaf = $implicit of ['π±', 'π', 'πΏ']; let i = index;
9. let leaf = $implicit; let i = index; of ['π±', 'π', 'πΏ'];
10. let leaf = $implicit, let i = index, of ['π±', 'π', 'πΏ'];
In fact, these *ngFor
syntaxes end up with the same result:
<ng-template ngFor let-leaf [ngForOf]="['π±', 'π', 'πΏ']" let-i="index">
...
</ng-template>
Optional Separators
One side note, maybe you've already figured out from these *ngFor
syntaxes above.
Just as the :
is optional in the a key expression
, all separators in the micro syntax are optional.
π Hey there
If you want to gain more insights into how Angular Structural Directives internals, you can reference my previous blog post Demystifying the Angular Structural Directives in a nutshell
Thank you for making it to the end
Thank you for choosing to read this blog post among the tens of thousands of great blog posts out there. And I will be really happy if you find something interesting from my blog post.
Reference
Top comments (0)