Angular 4.0にはいくつかの新しい機能が追加されます。 今回はngIf
に追加される新しい機能について解説します。
ngIfの新機能
ngIfThen
: テンプレート分離
これまでのngIf
で表示を切り替えられるのは、ngIf
ディレクティブが付与された要素とその内側の要素だけでした。 Angular 4.0以降は、ngIf
による条件付けと、その条件により制御されるテンプレートを分離できます。 次の例では、show
プロパティが真のときに#thenBlock
のテンプレートが描画されます。
<div *ngIf="show; then thenBlock">ignored</div><ng-template #thenBlock>show === true</ng-template>
then
テンプレートにはTemplateRef
のインスタンスを渡せます。null
のときは無視されます。 次の例では、条件によってngIf
によって描画されるテンプレートを切り替えています。 それほどユースケースは多くないですが、必要になる場面があるかもしれません。
@Component({
selector: 'ng-if-then',
template: `
<button (click)="switchPrimary()">Switch Template</button>
<div *ngIf="show; then thenBlock"></div>
<ng-template #primaryBlock>Primary</ng-template>
<ng-template #secondaryBlock>Secondary</ng-template>
`
})
class NgIfThenElse implements OnInit {
thenBlock: TemplateRef<any> = null;
show: boolean = true;
@ViewChild('primaryBlock')
primaryBlock: TemplateRef<any> = null;
@ViewChild('secondaryBlock')
secondaryBlock: TemplateRef<any> = null;
switchPrimary() {
this.thenBlock = this.thenBlock === this.primaryBlock ? this.secondaryBlock : this.primaryBlock;
}
ngOnInit() { this.thenBlock = this.primaryBlock; }
}
ngIfElse
: 偽のときのテンプレート
先ほどのthen
テンプレートはこのelse
テンプレートの副産物とも言えるでしょう。 その名前のとおり、ngIf
に渡された式が偽のときに描画されるテンプレートを指定する仕組みです。 else
テンプレートは次のように使います。
<div *ngIf="show; else elseBlock">show === true</div>
<ng-template #elseBlock>show === false</ng-template>
then
テンプレートとelse
テンプレートは併用できます。
<div *ngIf="show; then thenBlock; else elseBlock"></div>
<ng-template #thenBlock>show === true</ng-template>
<ng-template #elseBlock>show === false</ng-template>
これまでは真の場合と偽の場合にそれぞれ逆の条件のngIf
が必要でしたが、簡単に書けるようになります。
As
構文: 評価結果の変数化
これこそがngIf
最大の変更点です。 ngIf
に渡された式の評価結果をローカル変数にアサインできるようになりました。 これはasync
パイプとngIf
を併用するケースで絶大な効果を発揮します。 次の例を見てみましょう。 非同期にユーザー情報が得られるコンポーネントで、データ取得後に.name
プロパティを表示したいとき、 これまではこのようにasync
パイプと?.
構文を組み合わせていました。
<p>{{ (user$ | async)?.name }}</p>
これが.name
以外にも.age
や.icon
なども使いたいとなると、テンプレートは大変なことになります。
<p>{{ (user$ | async)?.name }}</p>
<p>{{ (user$ | async)?.age }}</p>
<img [src]="(user$ | async)?.icon">
せめて?.
をなくそうとngIf
で囲っても、async
パイプは全てのバインディングに必要です。
<div *ngIf="user$ | async">
<p>{{ (user$ | async).name }}</p>
<p>{{ (user$ | async).age }}</p>
<img [src]="(user$ | async).icon">
</div>
Angular 4.0以降は、as
を使うことで評価結果を変数として保持できます。つまり、user$ | async
の結果であるユーザーデータを同期的に扱えるようになります。具体的には、次のように書けます。
<div *ngIf="user$ | async as user">
<p>{{ user.name }}</p>
<p>{{ user.age }}</p>
<img [src]="user.icon">
</div>
Woohoo!!!!! :tada::tada::tada::tada::tada:
この変化は単にテンプレートがきれいになるだけでなく、async
パイプが減ることによるパフォーマンスの改善も得られます。 アプリケーションをObservableベースのリアクティブな設計したときも、テンプレートが自然に書けるようになります。
else
テンプレートと併用すれば、今まではとても複雑になっていたテンプレートが次のようにスッキリします。
<div *ngIf="user$ | async as user; else userNotFound">
<p>{{ user.name }}</p>
<p>{{ user.age }}</p>
<img [src]="user.icon">
</div>
<ng-template #userNotFound>
<p>not found</p>
</ng-template>
このas
構文はngFor
でも使用できます。
<div *ngFor="let user of (users$ | async) as users; index as i">
<span>{{ i + 1 }} / users.length</span>
<span>{{ user.name }}</span>
</div>
まとめ
-
then
テンプレートでテンプレートの分離と切り替えが可能になる -
else
テンプレートで偽のときのテンプレートを指定できる -
as
による変数化でasync
パイプとの親和性が改善される
Angular 4.0 Features