NG筆記18-訂閱屬性變更事件$watch()
0 |
KO是用ko.computed()及subscibe()追蹤ViewModel屬性變動做出反應,在NG中則可透過$scope.$watch()實現,寫法為$watch(觀察對象, 連動函式, 值比對開關)。
觀察對象可以是字串或函式,使用字串時完全比照data-bind="propName"的寫法,也支援運算,例如:"model.firstLame + model.lastName";若使用函式,輸入參數為$scope物件,再依需求傳回要觀察對象屬性或其組合運算內容,例如:function(scope) { return scope.firstName + model.lastName }。
連動函式規格為function(newVal, oldVal, scope),newValue即為前述關察對象字串或函式傳回結果。注意觀察對象函式會在每次$digest()時執行(例如:Scope其他屬性變動或ng-click、$apply()執行時),連動函式則在觀察對象改變時才觸發。另外,NG會一併傳回oldValue及整個Scope物件,以滿足複雜的應用情境。
值比對開關為Boolean,傳入true時,NG會改用angular.equals處理物件比對,新舊值可為不同物件,只要angular.equals()結果相等(物件各屬性都相同)就判為相等。但這種比對方式應用於大型或複雜物件時將耗用較多記憶體跟CPU,尤其在NG Dirty Check機制裡觀察對象字串或函式呼叫機率頗高,要小心對效能的影響。
以下是比照KO範例的簡單示範:
<!DOCTYPE html>
<html ng-app="sampleApp">
<head>
<meta charset="utf-8">
<title>Lab 18 - 訂閱屬性變更事件</title>
</head>
<body ng-controller="defaultCtrl">
<dl>
<dt>Name</dt>
<dd><input ng-model="model.name" /></dd>
<dt>Score</dt>
<dd><input ng-model="model.score" /></dd>
</dl>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js"></script>
<script>
angular.module("sampleApp", [])
.controller("defaultCtrl", function($scope) {
function myViewModel() {
var self = this;
self.name = "Jeffrey";
self.score = 32767;
}
var vm = new myViewModel();
$scope.model = vm;
//透過$watch關注Scope內屬性的變化
$scope.$watch("model.name", function(newValue, oldValue) {
console.log("name=" + newValue);
});
$scope.$watch(function(scope) {
return scope.model.score;
}, function(newValue, oldValue) {
console.log("score: " + oldValue + "->" + newValue);
});
});
</script>
</body>
</html>
這裡有個小問題。KO繫結<input>時預設onchange才會觸發重算(但可透過valueUpdate調整),比每按一個鍵就觸發一次連動有效率。但NG 1.2.*預設<input>一改變就連動,到1.3版才有updateOn參數可調,另一種做法是使用debounce設定將改變後延遲一段時間,累積多次變動只執行一次,也能解決問題,如以下示範:
<!DOCTYPE html>
<html ng-app="sampleApp">
<head>
<meta charset="utf-8">
<title>Lab 15 - 訂閱屬性變更事件</title>
</head>
<body ng-controller="defaultCtrl">
<dl>
<!-- ver 1.3+支援updateOn設定 -->
<dt>Name</dt>
<dd><input ng-model="model.name" ng-model-options="{ updateOn: 'blur' }" /></dd>
<dt>Score</dt>
<dd><input ng-model="model.score"
ng-model-options="{ updateOn: 'default', debounce: { default: 500 } }" /></dd>
</dl>
<div>
{{model.name}}
</div>
<script src="http://code.angularjs.org/1.3.0-beta.10/angular.js"></script>
<script>
angular.module("sampleApp", [])
.controller("defaultCtrl", function($scope) {
function myViewModel() {
var self = this;
self.name = "Jeffrey";
self.score = 32767;
}
var vm = new myViewModel();
$scope.model = vm;
//透過$watch關注Scope內屬性的變化
$scope.$watch("model.name", function(newValue, oldValue) {
console.log("name=" + newValue);
});
$scope.$watch(function(scope) {
return scope.model.score;
}, function(newValue, oldValue) {
console.log("score: " + oldValue + "->" + newValue);
});
});
</script>
</body>
</html>
Live Demo Name欄位要移開焦點才更新,Score欄位則是停頓超過0.5秒就觸發
[NG系列]
Comments
Be the first to post a comment