-
Notifications
You must be signed in to change notification settings - Fork 170
Expand file tree
/
Copy pathexpression.ngdoc
More file actions
154 lines (113 loc) · 9.99 KB
/
expression.ngdoc
File metadata and controls
154 lines (113 loc) · 9.99 KB
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
@ngdoc overview
@name Developer Guide: Выражения
@description
Выражения - это фрагменты кода в двойных фигурных скобках в JavaScript-стиле, обычно связанные с данными, например `{{ выражение }}`. Выражения обрабатываются сервисом {@link api/ng.$parse $parse}.
Пример валидных выражений в angular:
* `1+2`
* `3*10 | currency`
* `user.name`
## Отличие выражений Angular от выражений в JS
Заманчиво думать о выражениях Angular как о JavaScript выражения, но это не совсем корректно, так как Angular не использует JavaScript `eval()` для вычисления выражений. Вы можете думать о выражениях Angular как о JavaScript выражения со следующими отличиями:
* **Значение Атрибутов:** значение всех свойств вычисляются в области видимости в отличие от JavaScript, где выражения вычисляются в глобальном `window`.
* **Снисхождение:** вычисление выражений лояльно к неопределенным и нулевым значениям, в отличие от JavaScript, где такие вычисления выдадут исключение `NullPointerException`.
* **Последовательность действий не изменяется:** в Angular нельзя использовать условные операторы, циклы и исключения.
* **Фильтры:** можно передать результат вычисления выражений через цепочку фильтров. Например, чтобы преобразовать объект даты в специфичный для данного региона понятный человеку формат.
Если, с другой стороны, необходимо выполнить произвольный код JavaScript, нужно использовать метод контроллера и вызвать этот метод. Если необходимо выполнить `eval()` в выражении Angular из JavaScript, используйте метод {@link api/ng.$rootScope.Scope#$eval `$eval()`}.
## Example
<doc:example>
<doc:source>
1+2={{1+2}}
</doc:source>
<doc:scenario>
it('should calculate expression in binding', function() {
expect(binding('1+2')).toEqual('3');
});
</doc:scenario>
</doc:example>
Вы можете попробовать другие выражения:
<doc:example>
<doc:source>
<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>
<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>
</doc:source>
<doc:scenario>
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"]);
});
</doc:scenario>
</doc:example>
# Вычисление свойств
Оценка всех свойств происходит в области видимости. В отличие от JavaScript, где переменные по умолчанию являются глобальными свойством window, Выражения Angular должны использовать {@link api/ng.$window `$window`} чтобы сослаться на глобальный объект `window`. Например, если вы хотите вызвать `alert()`, которая определена в window, в выражении необходимо использовать `$window.alert()`. Это сделано намеренно, чтобы предотвратить случайный доступ к переменным глобального состояния (распространенный источник малозаметных ошибок).
<doc:example>
<doc:source>
<script>
function Cntl1($window, $scope){
$scope.name = 'World';
$scope.greet = function() {
($window.mockWindow || $window).alert('Hello ' + $scope.name);
}
}
</script>
<div class="example2" ng-controller="Cntl1">
Name: <input ng-model="name" type="text"/>
<button ng-click="greet()">Greet</button>
</div>
</doc:source>
<doc:scenario>
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');
});
</doc:scenario>
</doc:example>
## Снисходительность
Механизм вычисления выражений прощает неаккуратное использование null или undefined. В чистом JavaScript вычисление выражения `a.b.c` выбросит исключение в случае, если `a` не является объектом. И хотя это имеет смысл для серьёзного языка вроде JavaScript, выражения чаще всего используются для связки данных, которые обычно выглядят так:
{{a.b.c}}
В данном случае гораздо разумнее не показывать ничего, чем кидать исключение если `a` не определено (возможно, мы ожидаем ответ от сервера и вскоре a станет определено). Если бы механизм вычисления выражений не был таким снисходительным, нам бы пришлось писать что-то вроде `{{((a||{}).b||{}).c}}`. Ужасно, не правда ли?
Аналогично, вызов функции `a.b.c()` на неопределённом значении или на null-объекте просто-напросто возвращает undefined.
## Отсутствие управляющих выражений
Вы не можете управлять потоком вычисления внутри выражений. Причина - философия angular, которая утверждает, что логика должна быть внутри контроллеров, а не представлений. Если вам нужен if, цикл, или вы хотите бросить исключение из выражения - делегируйте всё это JavaScript-методу.
## Фильтры
Для показа данных пользователю, возможно, потребуется, преобразовать данные из сырого формата в формат удобный для пользователя. Например, у вас может быть объект данных, который должен быть отформатирован в соответствии с текущим языком, прежде чем показаться пользователю. Вы можете передать выражения через цепочку фильтров так:
name | uppercase
Вычислитель выражений просто передаёт значение фильтру {@link api/ng.filter:uppercase `uppercase`}.
Можно вызвать несколько фильтров, один за другим, используя синтаксис:
value | filter1 | filter2
В фильтры можно передавать аргументы, для этого используется знак двоеточия (:). Например, чтобы отобразить число 123 с двумя знаками после запятой используйте следующую конструкцию:
123 | number:2
# $
Удивлены, узнав что префикс $ имеет значение? Это просто префикс, который Angular использует, чтобы отделить имена своего API от других. Если в Angular не использовать $, то выражение `a.length()` вернет undefined, потому что ни a, ни Angular не определяют такое свойство.
Предположим, что в будущей версии Angular мы добавим метод length, и в этом случае поведение выражений изменится. Что еще хуже, если разработчик также создаст свойство length, то произойдет конфликт. Эта проблема существует, потому что аргументы Angular осуществляют объекты с дополнительным поведение. Добавляя $ в название метода мы резервируем пространство наших имен, так что разработчики Angular и программисты, которые используют Angular, могут работать не пересекаясь.