我正在使用angularJS 1.4.8,昨天我注意到$ scope。$ watch并没有触发每次导致我的应用程序出错的更改。
有没有办法强制它立即对每一个变化起作用? 就像在这段代码中一样,在消息的每一次更改中,我希望watch中的函数触发:
(function(){
angular.module('myApp', [])
.controller('myAppController', myAppController)
function myAppController($scope){
console.log('controller loading !');
$scope.message = 'message1';
$scope.$watch('message', function(newMessage){
console.log('newMessage', newMessage)
});
function changeMessage(){
$scope.message='hi';
$scope.message='hi12';
}
changeMessage();
}
})();
控制台将打印:
controller loading !
newMessage hi22
plunker link https://plnkr.co/edit/SA1AcIVwr04uIUQFixAO?p=preview
编辑: 我真的想知道是否有任何其他方法,而不是包装更改与超时和使用范围适用,在我的原始代码iv多个地方,我改变范围属性,我想避免使用这每个更改
答案 0 :(得分:11)
发生这种情况是因为只有在“摘要循环”之间更改了值时才会触发监视。
您的功能是在同一功能中更改示波器上的消息值。这将在同一个摘要循环中执行。
当角度移动到下一个循环时,它将只看到最后更改的值,在您的情况下将为hi22
。
Here's一篇很好的文章让这种行为变得清晰
答案 1 :(得分:5)
更新你的changeMessage函数,使其使用$ scope。$ apply函数,这将确保您的更改得到反映,并且angular知道您对变量的更改。
changeMessage() {
setTimeout(function () {
$scope.$apply(function () {
$scope.message = "Timeout called!";
});
}, 2000);
}
答案 2 :(得分:3)
如果将值更改为相同的摘要周期,则不会触发观察者并获取最后一个值。当我们运行$timeout
时,我们会在下一个摘要周期中更改$scope.message
值,并且观察者会按预期捕获它。
看一下简单的测试:
$scope.$watch(function(){
console.log('trigger');
return $scope.message;
},
function(newMessage){
console.log('newMessage', newMessage)
});
function changeMessage(){
$scope.message='hi';
$timeout(function(){
$scope.message='hi12';
});
}
输出:
controller loading !
trigger
newMessage hi
trigger
trigger
newMessage hi12
trigger
答案 3 :(得分:2)
$watch()
仅在每$digest()
之间触发。
Detailed explaination about the $apply()
and $digest()
在您的情况下,您会不断更新当前$scope.message
周期中的$digest()
。
您可以使用$scope
将每个新值应用于$apply()
来更改此设置。就像@Ajinkya写的那样。
唯一的问题是,将2000ms设置为超时,并不总是确保它在$digest()
之后执行。最重要的是,Angular具有内置超时功能。见下文。
(function(){
angular.module('myApp', [])
.controller('myAppController', myAppController)
function myAppController($scope, $timeout){
console.log('controller loading !');
$scope.message = 'message1';
$scope.$watch('message', function(newMessage){
console.log('newMessage', newMessage)
});
function changeMessage(){
setTimeout(function () {
$scope.$apply(function () {
$scope.message='hi12';
});
}, 2000);
}
changeMessage();
}
})();

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myAppController"></div>
&#13;
最好的方法是在$timeout
函数中调用构建,而不用以毫秒为单位设置时间。
这样,角度总是确保$timeout
将在最新的$digest()
之后运行。最重要的是。你不必使用$scope.$apply()
。因为$timeout
allready运行$digest()
,其中$scope.$apply()
手动调用新的$diggest()
周期。
(function(){
angular.module('myApp', [])
.controller('myAppController', myAppController)
function myAppController($scope, $timeout){
console.log('controller loading !');
$scope.message = 'message1';
$scope.$watch('message', function(newMessage){
console.log('newMessage', newMessage)
});
function changeMessage(){
$timeout(function () {
$scope.message='hi12';
});
}
changeMessage();
}
})();
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myAppController"></div>
&#13;
答案 4 :(得分:2)
无需在setTimeout和$ apply中同时包装changeMessage。如果您需要在执行前跳过一段时间,只需使用:
function changeMessage(){
$timeout(function(){
$scope.message = 'message';
}/* or add time here, doesn't matter */);
}
或者只是:
function changeMessage(){
$scope.message = 'message';
$scope.$apply();
}
两种方法最后调用$rootScope.$digest
。以下是更多信息:https://www.codingeek.com/angularjs/angular-js-apply-timeout-digest-evalasync/