事象
AngularのTemplate Syntaxである「?.
」(Safe Navigation Operator)で思わぬ障害を作りこんでしまいました。
Angularのテンプレートにて
<span *ngIf="obj.getData()?.indexOf(':') >= 0">
テスト
</span>
というコードを書きました。
コードの目的は、getData()
がnullでない場合、:
が文字列中に含まれるなら1「テスト」という文字列を出力し、その他の場合は、何も表示しないようにすることです。
getData()
は戻り値として、文字列を返します。ただし、nullを含むことがあります。
そこで、AngularのSafe Navigation Operator(getData()の直後の「?.
」)を用いて、
-
getData()
がnullでないなら以降の式を実行 - nullなら実行しない(
ngIf
全体でfalse)
となるようコーディングしたつもりでした。
しかし、getData()
の戻りがnullの場合でも、「テスト」が表示されてしまいました。
原因
Safe Navigation Operatorの仕様を勘違いしていたことです。
Safe Navigation Operatorはnull(またはundefined)の場合その後の式を評価しないのではなく、続くプロパティにアクセスしないことです2。
よって、getData()
がnullである場合、上記のコードは以下のように評価されます。
<span *ngIf="obj.getData() >= 0">
テスト
</span>
JavaScriptにおいて、>=
で比較する際に、0とnullは同じものとして評価されます。
よって上記の式の結果はtrue
となり、「テスト」の文字列が表示されてしまいました。
解消法
事前にnullの判定を入れました。
<ng-container *ngIf="obj.getData()">
<span *ngIf="obj.getData().indexOf(':') >= 0">
テスト
</span>
</ng-container>
-
そもそも「文字列中に含まれるかどうか」なら
String.prototype.includes()
を使いたいところなのですが、IE11対応がシステム要件に含まれるため、使えませんでした。 ↩ -
Angualrのドキュメントには「The expression bails out when it hits the first null value. 」とあります。 ↩