表達式
{{ 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"