根据$ watch的文档:
每次调用
watchExpression
和时都会调用$digest()
返回将要观看的值。
如果是这样,为什么这段代码会起作用? (jsbin)
$scope.$watch(function() {
var total = 0;
for (var i = 0; i < $scope.items.length; i++) {
total = total + $scope.items[i].price * $scope.items[i].quantity;
}
$scope.bill.total = total;
$scope.bill.discount = total > 100 ? 10 : 0;
$scope.bill.subtotal = total - $scope.bill.discount;
});
我在这里看不到任何return
。
并且文档明确表示应该返回值 - 应该返回。
答案 0 :(得分:2)
在每个digest
调用watch
。 watch
正在查看watchExpression
(通常是变量; $watch()
的第一个参数)是否已更改。在你的情况下,$watch()
的第一个参数是一个函数,而不是一个变量(这实际上不是问题,而是你的问题的原因:))。因此,每次调用digest
时,它都会执行watch
并执行您的函数。这就是它起作用的原因。
编辑:
你的那个函数可以或者应该有一个return
,它将返回一个变量,以便在执行return
语句之前监视你的函数中的任何代码。
答案 1 :(得分:1)
以下是关于摘要周期和观察者如何在Angular中工作的一些帖子:
* http://www.benlesh.com/2013/08/angularjs-watch-digest-and-apply-oh-my.html
* http://onehungrymind.com/notes-on-angularjs-scope-life-cycle/
重要的是要记住,在每个摘要周期中,Angular将始终至少运行一次watchExpression
。但如果listener
的值与前一次调用不同,它只会运行watchExpression
函数。
以下是一个简单示例,您希望将scope.otherCount
设置为与scope.count
相同的值。
$scope.count = 1;
$scope.otherCount = 0;
$scope.$watch(function(){
// This function is called multiple times every digest cycle.
// We should return a value to let Angular know when the listener needs to be run.
// If the return value of this function is different between two calls then the listener will run.
console.log('watchExpression');
// This is important for Angular to know that our watch value has changed.
return $scope.count;
}, function(newValue){
// When the value of `$scope.count` changes this listener will be run to update `$scope.otherCount`.
// The reason this listner is called is because our `watchExpression` above will
// have returned a different value.
$scope.otherCount = $scope.count;
console.log('count=', $scope.count);
console.log('count=', $scope.otherCount);
});
将它与手表相比较,你应该看看发生了什么。
我的回答中有一些我试图解决的隐藏问题:
您的示例是有效的JavaScript - 未明确返回值的函数的返回值为undefined
。
function a(){
// Don't return anything.
}
a() === undefined; // true
Angular会运行您的watchExpression
函数,并且每次都会从中获取值undefined
。就Angular而言,watchExpression
的值永远不会改变。
每次运行$scope
时都会更新watchExpression
,以便您在视图中看到正确的值。
但是,Angular在每个摘要周期中多次运行watchExpression
,这意味着$scope
的更新频率超出预期。
如果您使用 Angular 1.2 (或更高版本),那么您应该使用新的$scope.$watchCollection
方法来观察数组中的值:
$scope.$watchCollection('items', function(){
var total = 0;
for (var i = 0; i < $scope.items.length; i++) {
total = total + $scope.items[i].price * $scope.items[i].quantity;
}
$scope.bill.total = total;
$scope.bill.discount = total > 100 ? 10 : 0;
$scope.bill.subtotal = total - $scope.bill.discount;
});
这将监视$scope.items
数组,并在数组或数组中的项发生更改时运行侦听器函数。
如果您使用的是早期版本的角度(例如 Angular 1.0.x ),那么您需要找到一种不同的方式来触发重新计算:
<强> HTML:强>
在输入字段中添加ng-change
事件,并在其值发生更改时重新计算:
...
<div ng-repeat="item in items">
<span>{{item.title}}</span>
<!-- Add ng-change="itemChanged()" to the input -->
<input ng-model="item.quantity" ng-change="itemChanged()" />
<span>{{item.price | currency}}</span>
<span>{{item.price * item.quantity | currency}}</span>
</div>
...
<强> JavaScript的:强>
// Define a single function that is responsible for calculating the totals.
function calculateTotals(){
var total = 0;
for (var i = 0; i < $scope.items.length; i++) {
total = total + $scope.items[i].price * $scope.items[i].quantity;
}
$scope.bill.total = total;
$scope.bill.discount = total > 100 ? 10 : 0;
$scope.bill.subtotal = total - $scope.bill.discount;
}
// Add a $watch that will calculate the totals when the array length changes.
$scope.$watch('items', calculateTotals);
// Recalculate the totals when the input value changes.
$scope.itemChanged = function(){
calculateTotals();
};