Angular Directive Grammar & Microsyntax: Demystifying the Hidden Parts
Tags: angular, javascript, learning, programming
Published: 2023-11-03 07:44:40

### Introduction
```html
<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?

1. Is there any alternative `*ngFor` syntax?
2. Where does the `index` variable come from?
3. How does the `leaf` variable iterate over and reference items of `['🍀', '🍀🍀', '🍀🍀🍀']`?
4. Why is it _`let ... of ...`_? Can we change it to _`let ... something ...`_?

> **What do you think about trying the following syntaxes with `*ngFor`?**

```javascript
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_](https://stackblitz.com/edit/stackblitz-starters-hs3dvc?file=src%2Fmain.ts) link.
Surprisingly, these `peculiar syntaxes` compile without any errors. 🤔
How does this happen? What are the rules behind these syntax variations?

<hr />

### 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


![Angular microsyntax building blocks](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srxeioq3viuj4wkjr86r.png)

> #### 1. Expressions

Anything that, when referenced, returns a value.

- Raw value
```html
<p *hello="'👋 Hey there'"></p>
```
- Calling a function
```html
<p *hello="greeting()"></p>
```
- Referenced a variable
```html
<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`.
```html
<div *ngIf="(myFutureGirl$ | async) as myFutureGirl">
  {{myFutureGirl}}
<div>
```
```javacript
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:
```javascript
/**
 * 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:
```javascript
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:
```javascript
let leaf = $implicit
```
Angular automatically assigns the reference with the `$implicit` key in the context.

- **_Explicit_**
```javascript
let i = index
```
When we use `let i = index`, it is clear that the variable `i` references the `index` key in the context.

<hr />

### Combining Things Together

![A chart taking a microsyntax and turning it into a diagram. This diagram will be explained thoroughly via text in this section](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6g9d1kjogyepvms528os.png)

- 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:
```javascript
@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_.

```html
<!-- ✅ 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:
```javascript
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:
```javascript
<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.**

<hr/>

> 👋 **Hey there**

If you want to gain more insights into how Angular Structural Directives internals, you can reference my previous blog post
[<p *>Demystifying the Angular Structural Directives in a nutshell</p>](https://dev.to/khangtrannn/p-demystifying-the-angular-structural-directives-in-a-nutshell-1g61)

<hr />
> **_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.

<hr />

> **Reference**

[Angular Templates — From Start to Source](https://dev.to/this-is-angular/angular-templates-from-start-to-source-1db1)