diff options
| author | Misko Hevery | 2012-02-28 14:29:58 -0800 |
|---|---|---|
| committer | Misko Hevery | 2012-06-02 16:02:08 -0700 |
| commit | 41d26db32c1c013dd33faa03df85e38681a9ebb1 (patch) | |
| tree | a5be9c22e26b239129993fec416a16f33386a8c9 | |
| parent | dd38ce6585b0e7ffa755f4c65d78ed90204729d1 (diff) | |
| download | angular.js-41d26db32c1c013dd33faa03df85e38681a9ebb1.tar.bz2 | |
docs(expression): rewrite
| -rw-r--r-- | docs/content/guide/expression.ngdoc (renamed from docs/content/guide/dev_guide.expressions.ngdoc) | 130 | ||||
| -rw-r--r-- | src/ng/parse.js | 33 |
2 files changed, 69 insertions, 94 deletions
diff --git a/docs/content/guide/dev_guide.expressions.ngdoc b/docs/content/guide/expression.ngdoc index c54a9343..f92dbe48 100644 --- a/docs/content/guide/dev_guide.expressions.ngdoc +++ b/docs/content/guide/expression.ngdoc @@ -1,38 +1,41 @@ @ngdoc overview -@name Developer Guide: Understanding Angular Expressions +@name Developer Guide: Expressions @description -Expressions are {@link dev_guide.templates.databinding bindings} that you write in HTML and embed -in templates in order to create views in angular. Angular expressions are similar but not -equivalent to JavaScript expressions. +Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{ +expression }}`. Expressions are process by the {@link api/angular.module.ng.$parse $parse} +service. For example, these are all valid expressions in angular: -* `1+2={{1+2}}` -* `3*10|currency` -* `Hello {{name}}!` -* `Hello {{'World'}}!` + * `1+2` + * `3*10 | currency` + * `user.name` ## Angular Expressions vs. JS Expressions It might be tempting to think of angular view expressions as JavaScript expressions, but that is -not entirely correct. Angular does not use a simple JavaScript eval of the expression text. You can -think of angular expressions as JavaScript expressions with these differences: - -* **Attribute Evaluation:** evaluation of all attributes are against the current scope, not to the -global window as in JavaScript. -* **Forgiving:** expression evaluation is forgiving to undefined and null, unlike in JavaScript. -* **No Control Flow Statements:** you cannot do the following from an angular expression: -conditionals, loops, or throw. -* **Type Augmentation:** the scope expression evaluator augments built-in types. -* **Filters:** you can add filters to an expression, for example to convert raw data into a -human-readable format. -* **The $:** angular reserves this prefix to differentiate its API names from others. +not entirely correct, since angular does not use a JavaScript `eval()` to evaluate expressions. +You can think of angular expressions as JavaScript expressions with following differences +differences: + + * **Attribute Evaluation:** evaluation of all properties are against the scope, doing the + evaluation, unlike in JavaScript where the expressions are evaluated against the global + `window`. + + * **Forgiving:** expression evaluation is forgiving to undefined and null, unlike in JavaScript, + where such evaluations generate `NullPointerExceptions`. + + * **No Control Flow Statements:** you cannot do any of the following in angular expression: + conditionals, loops, or throw. + + * **Filters:** you can pass result of expression evaluations through filter chains. For example + to convert date object into a local specific human-readable format. If, on the other hand, you do want to run arbitrary JavaScript code, you should make it a -controller method and call that. If you want to `eval()` an angular expression from JavaScript, use -the `Scope:$eval()` method. +controller method and call the method. If you want to `eval()` an angular expression from +JavaScript, use the {@link api/angular.module.ng.$rootScope.Scope#$eval `$eval()`} method. ## Example <doc:example> @@ -86,13 +89,13 @@ You can try evaluating different expressions here: </doc:example> -# Attribute Evaluation +# Property Evaluation -Evaluation of all attributes takes place against the current scope. Unlike JavaScript, where names -default to global window properties, angular expressions have to use `$window` to refer to the -global object. For example, if you want to call `alert()`, which is defined on `window`, an -expression must use `$window.alert()`. This is done intentionally to prevent accidental access to -the global state (a common source of subtle bugs). +Evaluation of all properties takes place against a scope. Unlike JavaScript, where names default +to global window properties, angular expressions have to use {@link api/angular.module.ng.$window +`$window`} to refer to the global `window` object. For example, if you want to call `alert()`, which is +defined on `window`, in an expression must use `$window.alert()`. This is done intentionally to +prevent accidental access to the global state (a common source of subtle bugs). <doc:example> <doc:source> @@ -141,67 +144,13 @@ forgiving we'd have to write bindings that clutter the code, for example: `{{((a Similarly, invoking a function `a.b.c()` on undefined or null simply returns undefined. -Assignments work the same way in reverse: - - a.b.c = 10 - -...creates the intermediary objects even if a is undefined. - ## No Control Flow Statements 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 (including ternary operators), loop, or to throw from a view expression, delegate to a -JavaScript method instead. - - -## Type Augmentation - -Built-in types have methods like `[].push()`, but the richness of these methods is limited. -Consider the example below, which allows you to do a simple search over a canned set of contacts. -The example would be much more complicated if we did not have the `Array:$filter()`. There is no -built-in method on `Array` called {@link api/angular.module.ng.$filter.filter $filter} and angular doesn't add -it to `Array.prototype` because that could collide with other JavaScript frameworks. - -For this reason the scope expression evaluator augments the built-in types to make them act like -they have extra methods. The actual method for `$filter()` is `angular.module.ng.$filter.filter()`. You can -call it from JavaScript. - -Extensions: You can further extend the expression vocabulary by adding new methods to -`angular.module.ng.$filter` or `angular.String`, etc. +conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead. -<doc:example> -<doc:source> - <div ng-init="friends = [ - {name:'John', phone:'555-1212'}, - {name:'Mary', phone:'555-9876'}, - {name:'Mike', phone:'555-4321'}, - {name:'Adam', phone:'555-5678'}, - {name:'Julie', phone:'555-8765'}]"></div> - Search: <input ng-model="searchText"/> - <table class="example3"> - <thead> - <tr><th>Name</th><th>Phone</th><tr> - </thead> - <tbody> - <tr ng-repeat="friend in friends | filter:searchText"> - <td>{{friend.name}}</td> - <td>{{friend.phone}}</td> - </tr> - </tbody> - </table> -</doc:source> -<doc:scenario> - it('should filter the list', function() { - var tr = using('table.example3 tbody').repeater('tr'); - expect(tr.count()).toBe(5); - input('searchText').enter('a'); - expect(tr.count()).toBe(2); - - }); -</doc:scenario> -</doc:example> ## Filters @@ -212,14 +161,15 @@ of filters like this: name | uppercase -The expression evaluator simply passes the value of name to angular.module.ng.$filter.uppercase. +The expression evaluator simply passes the value of name to {@link +api/angular.module.ng.$filter.uppercase `uppercase`} filter. Chain filters using this syntax: value | filter1 | filter2 -You can also pass colon-delimited arguments to filters, for example, to display the number 123 with -2 decimal points: +You can also pass colon-delimited arguments to filters, for example, to display the number 123 +with 2 decimal points: 123 | number:2 @@ -235,11 +185,3 @@ property and then we would have a collision. This problem exists because angular objects with additional behavior. By prefixing its additions with $ we are reserving our namespace so that angular developers and developers who use angular can develop in harmony without collisions. - -## Related Topics - -* {@link dev_guide.templates.filters Understanding Angular Filters} - -## Related API - -* {@link api/angular.module.ng.$compile Angular Compiler API} diff --git a/src/ng/parse.js b/src/ng/parse.js index 294e2c8d..55b0c67c 100644 --- a/src/ng/parse.js +++ b/src/ng/parse.js @@ -807,6 +807,39 @@ function getterFn(path, csp) { /////////////////////////////////// +/** + * @ngdoc function + * @name angular.module.ng.$parse + * @function + * + * @description + * + * Converts Angular {@link guid/expression expression} into a function. + * + * <pre> + * var getter = $parse('user.name'); + * var setter = getter.assign; + * var context = {user:{name:'angular'}}; + * var locals = {user:{name:'local'}}; + * + * expect(getter(context)).toEqual('angular'); + * setter(context, 'newValue'); + * expect(context.user.name).toEqual('newValue'); + * expect(getter(context, locals)).toEqual('local'); + * </pre> + * + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context`: an object against which any expressions embedded in the strings are evaluated + * against (Topically a scope object). + * * `locals`: local variables context object, useful for overriding values in `context`. + * + * The return function also has an `assign` property, if the expression is assignable, which + * allows one to set values to expressions. + * + */ function $ParseProvider() { var cache = {}; this.$get = ['$filter', '$sniffer', function($filter, $sniffer) { |
