表达式
{{ expression }}
特性:
所有的表达式都在其所属的作用域内部执行,并有访问本地$scope的权限;
如果表达式发生了TypeError和ReferenceError并不会抛出异常;
不允许使用任何流程控制功能(条件控制,例如if/eles);
可以接受过滤器和过滤器链。
对表达式进行的任何操作,都会在其所属的作用域内部执行,因此可以在表达式内部调用那
些限制在此作用域内的变量,并进行循环、函数调用、将变量应用到数学表达式中等操作。
解析 AngularJS 表达式
将$parse服务注入到控制器中,然后调用它就可以实现手动解析表达式。举例来说,如果页
面上有一个输入框绑定到了expr变量上,如下所示:
AngularJS通过$parse这个内部服务来进行表达式的运算,这个服务能够访问当前所处的作
用域。这个过程允许我们访问定义在 $scope上的原始JavaScript数据和函数。
type="text"
placeholder="Enter an expression" />
{{ parseValue }}
我们可以在MyController中给expr这个表达式设置一个$watch并解析它:
angular.module("myApp", []).controller('MyController',
function($scope,$parse) {
$scope.$watch('expr', function(newVal, oldVal, scope) {
if (newVal !== oldVal) {
// 用该表达式设置parseFun
var parseFun = $parse(newVal);
// 获取经过解析后表达式的值
$scope.parsedValue = parseFun(scope);
}
});
});
插值字符串
在AngularJS中,我们的确有手动运行模板编译的能力。例如,插值允许基于作用域上的某
个条件实时更新文本字符串。
要在字符串模板中做插值操作,需要在你的对象中注入$interpolate服务。在下面的例子
中,我们将会将它注入到一个控制器中:
angular.module('myApp', [])
.controller('MyController',
function($scope, $interpolate) {
// 我们同时拥有访问$scope和$interpolate服务的权限
});
$interpolate服务是一个可以接受三个参数的函数,其中第一个参数是必需的。
text(字符串):一个包含字符插值标记的字符串。
mustHaveExpression(布尔型):如果将这个参数设为true,当传入的字符串中不含有表
达式时会返回null。
- trustedContext(字符串): AngularJS会对已经进行过字符插值操作的字符串通过$sec.getTrusted()方法进行严格的上下文转义。
$interpolate服务返回一个函数,用来在特定的上下文中运算表达式。
设置好这些参数后,就可以在控制器中进行字符插值的操作了。例如,假设我们希望可以在
电子邮件的正文中进行实时编辑,当文本发生变化时进行字符插值操作并将结果展示出来。
type="email"
placeholder="Recipient" />
{{ previewText }}
$watch函数会监视$scope上的某个属性。只要属性发生变化就会调用
对应的函数。可以使用$watch函数在$scope上某个属性发生变化时直接运行一个自定
义函数。
在控制器中,我们设置了$watch来监视邮件正文的变化,并将emailBody属性的值进行字符
插值后的结果赋值给previewText属性。
angular.module('myApp', [])
.controller('MyController', function($scope, $interpolate) {
// 设置监听
$scope.$watch('emailBody', function(body) {
if (body) {
var template = $interpolate(body);
$scope.previewText =
template({to: $scope.to});
}
};
});
现在,在{{ previewText }}内部的文本中可以将{{ to }}当做一个变量来使用,并对文本
的变化进行实时更新。
如果需要在文本中使用不同于{{ }}的符号来标识表达式的开始和结束,可以在
$inter polateProvider中配置。
用startSymbol()方法可以修改标识开始的符号。这个方法接受一个参数。
- value(字符型) :开始符号的值。
用endSymbol()方法可以修改标识结束的符号。这个方法也接受一个参数。
- value(字符型) : 结束符号的值。
如果要修改这两个符号的设置,需要在创建新模块时将$interpolateProvider注入进去。
下面我们来创建一个服务,第14章会对服务进行深入讨论。
angular.module('emailParser', [])
.config(['$interpolateProvider', function($interpolateProvider) {
$interpolateProvider.startSymbol('__');
$interpolateProvider.endSymbol('__');
}])
.factory('EmailParser', ['$interpolate', function($interpolate) {
// 处理解析的服务
return {
parse: function(text, context) {
var template = $interpolate(text);
return template(context);
}
};
}]);
现在,我们已经创建了一个模块,可以将它注入到应用中,并在邮件正文的文本中运行这个
邮件解析器:
angular.module('myApp', ['emailParser'])
.controller('MyController', ['$scope', 'EmailParser',
function($scope, EmailParser) {
// 设置监听
$scope.$watch('emailBody', function(body) {
if (body) {
$scope.previewText = EmailParser.parse(body, {
to: $scope.to
});
}
});
}]);
现在用自定义的 __ 符号取代默认语法中的 {{ }} 符号来请求插值文本。
由于我们将表达式开始和结束的符号都设置成了__,因此需要将HTML修改成用这个符号取
代{{ }}的版本
type="email"
placeholder="Recipient" />
__ previewText __
更简单的例子
在AngularJS中使用字符串模板
如果你曾经使用过Handlerbars等模板引擎,你一定会觉得在AngularJS中进行开发非常的爽。在AngularJS中,你可以直接将DOM当做模板来使用,比如下面的例子:
My name is {{name}}
在AngularJS对页面施展魔法时,它会自动将{{name}}替换为当前作用域中的name属性值。这实在是太方便了,我们再也不需要在页面中加入\或者\来预定义我们的模板,并在需要使用时将它插入页面里面了。
但是,有时还是想要使用字符串模板,比如说要根据用户生成的具体数据来生成模板,而不是预先在DOM中定义的情况。在AngularJS中,这种情况也能轻松的得到解决,我们可以使用AngularJS内置的$interpolate service来达成我们的目标,具体代码如下:
angular.module('myapp',[])
.controller('myctrl',function($scope,$interpolate){
var tmp = $interpolate('Publish by {{name}} on {{date}}');
var data1 = {name: 'Mike',date: '2014-1-1'};
var data2 = {name: 'Karen',date: '2014-1-2'};
var str1 = tmp(data1);
var str2 = tmp(data2);
});
上面的例子非常简单,如果你曾经使用过其他的模板引擎,你会发现$interpolate()就相当于Handlerbars里面的Handlebars.compile()函数,或者是underscore中的_.template函数()。它们都是接收一个包含插值占位符的字符串,然后返回一个函数,接着我们只需要将插值的对象传递给这个函数,就能得到一个经过插值之后的字符串。
另外,在$interpolate中,我们也同样能够使用过滤器,比如下面的例子:
var template = $interpolate( 'Published by {{name|uppercase}} on {{date}}' );
var str = template( { name: 'Mike', date: '2013-11-25' } );
// str == "Published by MIKE on 2013-11-25"