forked from angular/code.angularjs.org
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexpression.html
162 lines (158 loc) · 8.57 KB
/
expression.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<a href="http://github.com/angular/angular.js/edit/master/docs/content/guide/expression.ngdoc" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable=""></code>
<div><span class="hint"></span>
</div>
</h1>
<div><div class="developer-guide-page developer-guide-expressions-page"><p>Expressions are JavaScript-like code snippets that are usually placed in bindings such as <code>{{
expression }}</code>. Expressions are processed by the <a href="api/ng.$parse"><code>$parse</code></a>
service. Expressions are often post processed using <a href="guide/filter">filters</a> to create a more user-friendly format.</p>
<p>For example, these are all valid expressions in angular:</p>
<ul>
<li><code>1+2</code></li>
<li><code>user.name</code></li>
</ul>
<h3 id="angular-expressions-vs-js-expressions">Angular Expressions vs. JS Expressions</h3>
<p>It might be tempting to think of Angular view expressions as JavaScript expressions, but that is
not entirely correct, since Angular does not use a JavaScript <code>eval()</code> to evaluate expressions.
You can think of Angular expressions as JavaScript expressions with following differences:</p>
<ul>
<li><p><strong>Attribute Evaluation:</strong> evaluation of all properties are against the scope, doing the
evaluation, unlike in JavaScript where the expressions are evaluated against the global
<code>window</code>.</p>
</li>
<li><p><strong>Forgiving:</strong> expression evaluation is forgiving to <code>undefined</code> and <code>null</code>, unlike in JavaScript,
where trying to evaluate undefined properties can generate <code>ReferenceError</code> or <code>TypeError</code>.</p>
</li>
<li><p><strong>No Control Flow Statements:</strong> you cannot do any of the following in angular expression:
conditionals, loops, or throw.</p>
</li>
</ul>
<p>If, on the other hand, you do want to run arbitrary JavaScript code, you should make it a
controller method and call the method. If you want to <code>eval()</code> an angular expression from
JavaScript, use the <a href="api/ng.$rootScope.Scope#methods_$eval"><code><code>$eval()</code></code></a> method.</p>
<h3 id="example">Example</h3>
<h3 id="source">Source</h3>
<div source-edit="" source-edit-deps="angular.js" source-edit-html="index.html-218" source-edit-css="" source-edit-js="" source-edit-json="" source-edit-unit="" source-edit-scenario="scenario.js-219"></div>
<div class="tabbable"><div class="tab-pane" title="index.html">
<pre class="prettyprint linenums" ng-set-text="index.html-218" ng-html-wrap=" angular.js"></pre>
<script type="text/ng-template" id="index.html-218">
1+2={{1+2}}
</script>
</div>
<div class="tab-pane" title="End to end test">
<pre class="prettyprint linenums" ng-set-text="scenario.js-219"></pre>
<script type="text/ng-template" id="scenario.js-219">
it('should calculate expression in binding', function() {
expect(binding('1+2')).toEqual('3');
});
</script>
</div>
</div><h3 id="demo">Demo</h3>
<div class="well doc-example-live animate-container" ng-embed-app="" ng-set-html="index.html-218" ng-eval-javascript=""></div>
<p>You can try evaluating different expressions here:</p>
<h3 id="source">Source</h3>
<div source-edit="" source-edit-deps="angular.js script.js" source-edit-html="index.html-221" source-edit-css="" source-edit-js="script.js-220" source-edit-json="" source-edit-unit="" source-edit-scenario="scenario.js-222"></div>
<div class="tabbable"><div class="tab-pane" title="index.html">
<pre class="prettyprint linenums" ng-set-text="index.html-221" ng-html-wrap=" angular.js script.js"></pre>
<script type="text/ng-template" id="index.html-221">
<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 track by $index">
[ <a href="" ng-click="removeExp($index)">X</a> ]
<tt>{{expr}}</tt> => <span ng-bind="$parent.$eval(expr)"></span>
</li>
</ul>
</div>
</script>
</div>
<div class="tab-pane" title="script.js">
<pre class="prettyprint linenums" ng-set-text="script.js-220"></pre>
<script type="text/ng-template" id="script.js-220">
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>
</div>
<div class="tab-pane" title="End to end test">
<pre class="prettyprint linenums" ng-set-text="scenario.js-222"></pre>
<script type="text/ng-template" id="scenario.js-222">
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"]);
});
</script>
</div>
</div><h3 id="demo">Demo</h3>
<div class="well doc-example-live animate-container" ng-embed-app="" ng-set-html="index.html-221" ng-eval-javascript="script.js-220"></div>
<h2 id="property-evaluation">Property Evaluation</h2>
<p>Evaluation of all properties takes place against a scope. Unlike JavaScript, where names default
to global window properties, Angular expressions have to use <a href="api/ng.$window"><code><code>$window</code></code></a> to refer to the global <code>window</code> object. For example, if you want to call <code>alert()</code>, which is
defined on <code>window</code>, in an expression you must use <code>$window.alert()</code>. This is done intentionally to
prevent accidental access to the global state (a common source of subtle bugs).</p>
<h3 id="property-evaluation_source">Source</h3>
<div source-edit="" source-edit-deps="angular.js script.js" source-edit-html="index.html-224" source-edit-css="" source-edit-js="script.js-223" source-edit-json="" source-edit-unit="" source-edit-scenario="scenario.js-225"></div>
<div class="tabbable"><div class="tab-pane" title="index.html">
<pre class="prettyprint linenums" ng-set-text="index.html-224" ng-html-wrap=" angular.js script.js"></pre>
<script type="text/ng-template" id="index.html-224">
<div class="example2" ng-controller="Cntl1">
Name: <input ng-model="name" type="text"/>
<button ng-click="greet()">Greet</button>
</div>
</script>
</div>
<div class="tab-pane" title="script.js">
<pre class="prettyprint linenums" ng-set-text="script.js-223"></pre>
<script type="text/ng-template" id="script.js-223">
function Cntl1($window, $scope){
$scope.name = 'World';
$scope.greet = function() {
($window.mockWindow || $window).alert('Hello ' + $scope.name);
}
}
</script>
</div>
<div class="tab-pane" title="End to end test">
<pre class="prettyprint linenums" ng-set-text="scenario.js-225"></pre>
<script type="text/ng-template" id="scenario.js-225">
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');
});
</script>
</div>
</div><h3 id="property-evaluation_demo">Demo</h3>
<div class="well doc-example-live animate-container" ng-embed-app="" ng-set-html="index.html-224" ng-eval-javascript="script.js-223"></div>
<h3 id="property-evaluation_forgiving">Forgiving</h3>
<p>Expression evaluation is forgiving to undefined and null. In JavaScript, evaluating <code>a.b.c</code> throws
an exception if <code>a</code> is not an object. While this makes sense for a general purpose language, the
expression evaluations are primarily used for data binding, which often look like this:</p>
<pre><code> {{a.b.c}}</code></pre>
<p>It makes more sense to show nothing than to throw an exception if <code>a</code> is undefined (perhaps we are
waiting for the server response, and it will become defined soon). If expression evaluation wasn't
forgiving we'd have to write bindings that clutter the code, for example: <code>{{((a||{}).b||{}).c}}</code></p>
<p>Similarly, invoking a function <code>a.b.c()</code> on undefined or null simply returns undefined.</p>
<h3 id="property-evaluation_no-control-flow-statements">No Control Flow Statements</h3>
<p>You cannot write a control flow statement in an expression. The reason behind this is core to the
Angular philosophy that application logic should be in controllers, not in the view. If you need a
conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead.</p>
</div></div>