| <a href='http://github.com/angular/angular.js/edit/master/docs/content/guide/expression.ngdoc' class='improve-docs btn btn-primary'><i class="glyphicon glyphicon-edit"> </i>Improve this doc</a> |
| |
| |
| <h1 id="angular-expressions">Angular Expressions</h1> |
| <p>Angular expressions are JavaScript-like code snippets that are usually placed in bindings such as |
| <code>{{ expression }}</code>.</p> |
| <p>For example, these are valid expressions in Angular:</p> |
| <ul> |
| <li><code>1+2</code></li> |
| <li><code>a+b</code></li> |
| <li><code>user.name</code></li> |
| <li><code>items[index]</code></li> |
| </ul> |
| <h2 id="angular-expressions-vs-javascript-expressions">Angular Expressions vs. JavaScript Expressions</h2> |
| <p>Angular expressions are like JavaScript expressions with the following differences:</p> |
| <ul> |
| <li><p><strong>Context:</strong> JavaScript expressions are evaluated against the global <code>window</code>. |
| In Angular, expressions are evaluated against a <a href="api/ng/type/$rootScope.Scope"><code>scope</code></a> object.</p> |
| </li> |
| <li><p><strong>Forgiving:</strong> In JavaScript, trying to evaluate undefined properties generates <code>ReferenceError</code> |
| or <code>TypeError</code>. In Angular, expression evaluation is forgiving to <code>undefined</code> and <code>null</code>.</p> |
| </li> |
| <li><p><strong>No Control Flow Statements:</strong> you cannot use the following in an Angular expression: |
| conditionals, loops, or exceptions.</p> |
| </li> |
| <li><p><strong>Filters:</strong> You can use <a href="guide/filter">filters</a> within expressions to format data before |
| displaying it.</p> |
| </li> |
| </ul> |
| <p>If you want to run more complex JavaScript code, you should make it a controller method and call |
| the method from your view. If you want to <code>eval()</code> an Angular expression yourself, use the |
| <a href="api/ng/type/$rootScope.Scope#$eval"><code>$eval()</code></a> method.</p> |
| <h2 id="example">Example</h2> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-example92@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-example92"> |
| |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code>1+2={{1+2}}</code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="protractor.js" |
| type="protractor" |
| language="js"> |
| <pre><code>it('should calculate expression in binding', function() { expect(element(by.binding('1+2')).getText()).toEqual('1+2=3'); });</code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-example92/index.html" name="example-example92"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <p>You can try evaluating different expressions here:</p> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-example93@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-example93"> |
| |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code><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></code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="script.js" |
| language="js" |
| type="js"> |
| <pre><code>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); }; }</code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="protractor.js" |
| type="protractor" |
| language="js"> |
| <pre><code>it('should allow user expression testing', function() { element(by.css('.expressions button')).click(); var lis = element(by.css('.expressions ul')).element.all(by.repeater('expr in exprs')); expect(lis.count()).toBe(1); expect(lis.get(0).getText()).toEqual('[ X ] 3*10|currency => $30.00'); });</code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-example93/index.html" name="example-example93"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <h2 id="context">Context</h2> |
| <p>Angular does not use JavaScript's <code>eval()</code> to evaluate expressions. Instead Angular's |
| <a href="api/ng/service/$parse">$parse</a> service processes these expressions.</p> |
| <p>Unlike JavaScript, where names default to global <code>window</code> properties, Angular expressions must use |
| <a href="api/ng/service/$window"><code>$window</code></a> explicitly to refer to the global <code>window</code> object. For example, if you |
| want to call <code>alert()</code> in an expression you must use <code>$window.alert()</code>. This restriction is |
| intentional. It prevents accidental access to the global state – a common source of subtle bugs.</p> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-example94@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-example94"> |
| |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code><div class="example2" ng-controller="Cntl1"> Name: <input ng-model="name" type="text"/> <button ng-click="greet()">Greet</button> </div></code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="script.js" |
| language="js" |
| type="js"> |
| <pre><code>function Cntl1($window, $scope){ $scope.name = 'World'; $scope.greet = function() { $window.alert('Hello ' + $scope.name); }; }</code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="protractor.js" |
| type="protractor" |
| language="js"> |
| <pre><code>it('should calculate expression in binding', function() { if (browser.params.browser == 'safari') { // Safari can't handle dialogs. return; } element(by.css('[ng-click="greet()"]')).click(); var alertDialog = browser.switchTo().alert(); expect(alertDialog.getText()).toEqual('Hello World'); alertDialog.accept(); });</code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-example94/index.html" name="example-example94"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <h2 id="forgiving">Forgiving</h2> |
| <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 <code>undefined</code> or <code>null</code> simply returns <code>undefined</code>.</p> |
| <h2 id="no-control-flow-statements">No Control Flow Statements</h2> |
| <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 the views. If you need a |
| conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead.</p> |
| <h2 id="-event-"><code>$event</code></h2> |
| <p>Directives like <a href="api/ng/directive/ngClick"><code>ngClick</code></a> and <a href="api/ng/directive/ngFocus"><code>ngFocus</code></a> |
| expose a <code>$event</code> object within the scope of that expression.</p> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-example95@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-example95" |
| module="eventExampleApp"> |
| |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code><div ng-controller="EventController"> <button ng-click="clickMe($event)">Event</button> <p><code>$event</code>: <pre> {{$event | json}}</pre></p> <p><code>clickEvent</code>: <pre>{{clickEvent | json}}</pre></p> </div></code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="script.js" |
| language="js" |
| type="js"> |
| <pre><code>angular.module('eventExampleApp', []). controller('EventController', ['$scope', function($scope) { /* * expose the event object to the scope */ $scope.clickMe = function(clickEvent) { $scope.clickEvent = simpleKeys(clickEvent); console.log(clickEvent); }; /* * return a copy of an object with only non-object keys * we need this to avoid circular references */ function simpleKeys (original) { return Object.keys(original).reduce(function (obj, key) { obj[key] = typeof original[key] === 'object' ? '{ ... }' : original[key]; return obj; }, {}); } }]);</code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-example95/index.html" name="example-example95"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <p>Note in the example above how we can pass in <code>$event</code> to <code>clickMe</code>, but how it does not show up |
| in <code>{{$event}}</code>. This is because <code>$event</code> is outside the scope of that binding.</p> |
| |
| |