式(Expressions)
概要
式(Expressions)は、{{式}}のようにして配置するのJavaScriptライクなコードの断片です。 式は$parseサービスによって処理されます。
例えば、下記は全てAngular内で有効な式になります。
- 1+2
- 3*10 | currency
- user.name
Angular式 vs JavaScript式
AngularのViewの式を、JavaScript式と同じものとして考えたくなるかもしれませんが、
AngularはJavaScriptのeval()
で式を評価しているわけでは無いので、完全に同じではありません。
JavaScriptの式とAngularの式の違いについて、下記の事を考慮しておくと良いでしょう。
もし、任意のJavaScriptコードを実行したい場合は、
それをコントローラーメソッドにして、そのメソッドを呼び出すべきです。
もし、Angularの式をJavaScriptからeval()
したい場合は、$eval()
メソッドを使用します。
サンプル
<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/1.2.0-rc.2/angular.min.js"></script>
</head>
<body>
1+2={{1+2}}
</body>
</html>
it('should calculate expression in binding', function() {
expect(binding('1+2')).toEqual('3');
});
<!doctype html> <html ng-app> <head> <script src="http://code.angularjs.org/1.2.0-rc.2/angular.min.js"></script> </head> <body> 1+2={{1+2}} </body> </html>
下記のデモは、入力欄から任意の式を試すことが可能です。
<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/1.2.0-rc.2/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="Cntl2" class="expressions">
Expression:
<input type='text' ng-model="expr" size="80"/>
<button ng-click="addExp(expr)">Evaluate</button>
<ul>
<li ng-repeat="expr in exprs">
[ <a href="" ng-click="removeExp($index)">X</a> ]
<tt>{{expr}}</tt> => <span ng-bind="$parent.$eval(expr)"></span>
</li>
</ul>
</div>
</body>
</html>
function Cntl2($scope) {
var exprs = $scope.exprs = [];
$scope.expr = '3*10|currency';
$scope.addExp = function(expr) {
exprs.push(expr);
};
$scope.removeExp = function(index) {
exprs.splice(index, 1);
};
}
it('should allow user expression testing', function() {
element('.expressions :button').click();
var li = using('.expressions ul').repeater('li');
expect(li.count()).toBe(1);
expect(li.row(0)).toEqual(["3*10|currency", "$30.00"]);
});
<!doctype html> <html ng-app> <head> <script src="http://code.angularjs.org/1.2.0-rc.2/angular.min.js"></script> <script>function Cntl2($scope) { var exprs = $scope.exprs = []; $scope.expr = '3*10|currency'; $scope.addExp = function(expr) { exprs.push(expr); }; $scope.removeExp = function(index) { exprs.splice(index, 1); }; } </script> </head> <body> <div ng-controller="Cntl2" class="expressions"> Expression: <input type='text' ng-model="expr" size="80"/> <button ng-click="addExp(expr)">Evaluate</button> <ul> <li ng-repeat="expr in exprs"> [ <a href="" ng-click="removeExp($index)">X</a> ] <tt>{{expr}}</tt> => <span ng-bind="$parent.$eval(expr)"></span> </li> </ul> </div> </body> </html>
プロパティの評価
全てのプロパティの評価は、スコープに対してのものに置き換えられます。
デフォルトでグローバルのwindow
のプロパティを参照するJavaScriptと異なり、
Angular式で、グローバルwinodw
オブジェクトを参照するには$window
を使用しなければいけません。
例えば、もしwindow
に定義されているalert()
をAngular式内で呼び出したい場合、
$window.alert()
を使用しなければいけません。
これはグローバル空間での衝突などの事故や見つけにくいバグを生み出す事を意図的に防ぐために行います。
<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/1.2.0-rc.2/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div class="example2" ng-controller="Cntl1">
Name: <input ng-model="name" type="text"/>
<button ng-click="greet()">Greet</button>
</div>
</body>
</html>
function Cntl1($window, $scope){
$scope.name = 'World';
$scope.greet = function() {
($window.mockWindow || $window).alert('Hello ' + $scope.name);
}
}
it('should calculate expression in binding', function() {
var alertText;
this.addFutureAction('set mock', function($window, $document, done) {
$window.mockWindow = {
alert: function(text){ alertText = text; }
};
done();
});
element(':button:contains(Greet)').click();
expect(this.addFuture('alert text', function(done) {
done(null, alertText);
})).toBe('Hello World');
});
<!doctype html> <html ng-app> <head> <script src="http://code.angularjs.org/1.2.0-rc.2/angular.min.js"></script> <script>function Cntl1($window, $scope){ $scope.name = 'World'; $scope.greet = function() { ($window.mockWindow || $window).alert('Hello ' + $scope.name); } } </script> </head> <body> <div class="example2" ng-controller="Cntl1"> Name: <input ng-model="name" type="text"/> <button ng-click="greet()">Greet</button> </div> </body> </html>
許容する式について
Angular式はundefined
とnull
の評価を許容します。
JavaScriptでは、もしa
がオブジェクトで無ければ、a.b.c
を評価した際に例外をスローします。
これは一般的な言語では理にかなっていますが、Angular式の評価の本来の目的は、下記のようなデータの紐付けに使用されるためです。
{{a.b.c}}
もし、undefined
であるならば、例外をスローするより何も表示しない方が理にかなっています。
(もしかしたら、サーバーレスポンスを待ち受けていて、そのうちに定義されるのかもしれないので)
もし、このような許容を行わないと、例えば{{((a||{}).b||{}).c}}
のような冗長なコードを書かなければいけなくなります。
同様にundefined
またはnull
のオブジェクト上で、a.b.c()
を呼び出した場合、
単にundefined
を返します。
制御できないフロー式について
Angularのビューの式では、フローを制御する文を書くことは出来ません。 これはAngularのコアとなる、「アプリケーションロジックはビューではなくコントローラーに書くべき」という、Angularの哲学に基づくためです。 もし、条件、ループ、スローをビューの式で必要な場合は、代わりにJavaScriptに委譲します。
フィルターについて
ユーザーに対してデータが提供される際に、ユーザーにとって分かりやすいフォーマットに変換する必要があるかもしれません。 例えば、ユーザーに対して表示する前に、ロケールに沿ったデータにする必要あるかもしれません。 下記のように、フィルターのチェインを通して式に渡すことが可能です。
name | uppercase
この式の評価は、単にname
の値が渡され、大文字化のフィルターが適用されます。
チェインフィルターは、下記の文法で使用します。
value | filter1 | filter2
また、コロン区切りで引数をフィルターに渡すことが可能です。 例えば、下記は少数第2位までの数字123を表示します。
123 | number:2
$について
あなたは、$
プレフィックが何なのか疑問に思ったかもしれません。
これは単にAngularが使用するプレフィックスで、その他のAPI名と区別するためです。
仮にAngularが$
を使用しないとして、a.length()
はAngularはそのようなプロパティを定義していないため、
undefined
を返します。
Angularの将来のバージョンを考慮すると、式の挙動を変更するようなケースで、
我々はlength
メソッドを追加するという選択をするかもしれません。
更に悪いことに、あなた(開発者)はlength
プロパティを作ることが可能で、これらは衝突することになるでしょう。
Angularがオブジェクトに対して振る舞いを追加するとなると、こういった問題に直面します。
我々は$
プレフィックスを追加することによって名前空間の予約を行い、Angularの開発者とAngularを使用する開発者の間で、
名前の衝突を起こさずに開発が出来るようにしています。
© 2017 Google
Licensed under the Creative Commons Attribution License 3.0.
このページは、ページトップのリンク先のAngularJS公式ドキュメント内のページを翻訳した内容を基に構成されています。 下記の項目を確認し、必要に応じて公式のドキュメントをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。
- AngularJSの更新頻度が高いため、元のコンテンツと比べてドキュメントの情報が古くなっている可能性があります。
- "訳注:"などの断わりを入れた上で、日本人向けの情報やより分かり易くするための追記を行っている事があります。