Dev Study
← Angular コース

70. *ngIf と *ngFor — @if / @for 以前の制御フロー

制御フローのセクションで学んだ @if / @for / @switch は、比較的新しい構文です。それ以前の長い期間、条件分岐や繰り返しは *ngIf・*ngFor・*ngSwitch という、* 付きのディレクティブで書かれていました。既存プロジェクトのテンプレートは大半がこちらなので、対訳を頭に入れておきましょう。もう1つの違いとして、これらは CommonModule を imports しないと使えませんでした。テンプレートに *ngIf があるのに動かない、というときは import 忘れが定番の原因でした。

対訳の基本はこうです。@if (cond) は *ngIf="cond"。else の分岐は @else のようなブロックではなく、<ng-template #empty> で作った下書きを *ngIf="cond; else empty" と名前で参照する形でした。@for (item of items; track item.id) は *ngFor="let item of items; trackBy: byId" で、track に式を書く代わりに、コンポーネント側に byId(index, item) { return item.id; } という関数を定義して渡します。インデックスは let i = index と書きました。

頻出イディオムも1つ覚えておきましょう。*ngIf="user$ | async as user" は、「asyncパイプで取り出した値に user という名前を付けて、値があるときだけ表示する」という購読と分岐の合わせ技で、旧コードのいたるところに出てきます。@if (user$ | async; as user) がその現代版です。なお、既存コードの一括変換には ng generate @angular/core:control-flow という公式の自動移行コマンドがあります。読めれば十分、書くのは @ 構文で、が基本方針です。

サンプルコード(フレームワーク環境が必要なため表示のみ)

<!-- ── 旧: *ngIf / *ngFor(既存コードで読む)── -->
<div *ngIf="user$ | async as user; else loading">
  <p>{{ user.name }}</p>
</div>
<ng-template #loading><p>読み込み中...</p></ng-template>

<li *ngFor="let item of items; let i = index; trackBy: byId">
  {{ i }}: {{ item.name }}
</li>

<!-- ── 新: @if / @for(自分で書く)── -->
<!-- @if (user$ | async; as user) {
       <p>{{ user.name }}</p>
     } @else {
       <p>読み込み中...</p>
     }
     @for (item of items; track item.id; let i = $index) {
       <li>{{ i }}: {{ item.name }}</li>
     } -->
サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗