如何$scope.$watch
在 Angular 中使用多个变量,并在其中一个变量发生变化时触发回调。
$scope.name = ...
$scope.age = ...
$scope.$watch('???',function(){
//called when name or age changed
})
如何$scope.$watch
在 Angular 中使用多个变量,并在其中一个变量发生变化时触发回调。
$scope.name = ...
$scope.age = ...
$scope.$watch('???',function(){
//called when name or age changed
})
更新
Angular 现在提供了两种范围方法$watchGroup(从 1.3 开始)和$watchCollection。@blazemonger 和@kargold 已经提到了这些。
这应该独立于类型和值工作:
$scope.$watch('[age,name]', function () { ... }, true);
在这种情况下,您必须将第三个参数设置为 true。
'age + name'
在这种情况下,字符串连接将失败:
<button ng-init="age=42;name='foo'" ng-click="age=4;name='2foo'">click</button>
在用户单击按钮之前,监视的值将是42foo
( 42
+ foo
),在单击之后是42foo
( 4
+ 2foo
)。所以不会调用 watch 函数。因此,如果您无法确保不会出现这种情况,则最好使用数组表达式。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" rel="stylesheet" />
<script src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
<script src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script>
<script src="http://code.angularjs.org/1.2.0-rc.2/angular.js"></script>
<script src="http://code.angularjs.org/1.2.0-rc.2/angular-mocks.js"></script>
<script>
angular.module('demo', []).controller('MainCtrl', function ($scope) {
$scope.firstWatchFunctionCounter = 0;
$scope.secondWatchFunctionCounter = 0;
$scope.$watch('[age, name]', function () { $scope.firstWatchFunctionCounter++; }, true);
$scope.$watch('age + name', function () { $scope.secondWatchFunctionCounter++; });
});
describe('Demo module', function () {
beforeEach(module('demo'));
describe('MainCtrl', function () {
it('watch function should increment a counter', inject(function ($controller, $rootScope) {
var scope = $rootScope.$new();
scope.age = 42;
scope.name = 'foo';
var ctrl = $controller('MainCtrl', { '$scope': scope });
scope.$digest();
expect(scope.firstWatchFunctionCounter).toBe(1);
expect(scope.secondWatchFunctionCounter).toBe(1);
scope.age = 4;
scope.name = '2foo';
scope.$digest();
expect(scope.firstWatchFunctionCounter).toBe(2);
expect(scope.secondWatchFunctionCounter).toBe(2); // This will fail!
}));
});
});
(function () {
var jasmineEnv = jasmine.getEnv();
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function (spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
</head>
<body></body>
</html>
http://plnkr.co/edit/2DwCOftQTltWFbEDiDlA?p=preview
PS:
正如@reblace 在评论中所述,当然可以访问这些值:
$scope.$watch('[age,name]', function (newValue, oldValue) {
var newAge = newValue[0];
var newName = newValue[1];
var oldAge = oldValue[0];
var oldName = oldValue[1];
}, true);
$scope.$watch('age + name', function () {
//called when name or age changed
});
Angular 1.3 专门为此目的提供了 $watchGroup:
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watchGroup
这似乎提供了与表达式数组上的标准 $watch 相同的最终结果。我喜欢它,因为它使代码中的意图更加清晰。
没有人提到明显的:
var myCallback = function() { console.log("name or age changed"); };
$scope.$watch("name", myCallback);
$scope.$watch("age", myCallback);
这可能意味着更少的轮询。如果您同时观看name + age
(为此)和name
(其他地方),那么我认为 Angular 会有效地查看name
两次以查看它是否脏。
按名称使用回调而不是内联它可以说更具可读性。特别是如果你能给它一个比我的例子更好的名字。
如果需要,您可以通过不同方式查看值:
$scope.$watch("buyers", myCallback, true);
$scope.$watchCollection("sellers", myCallback);
$watchGroup
如果您可以使用它很好,但据我所知,它不会让您将组成员视为集合或对象相等。
如果您在同一个回调函数调用中需要两个表达式的旧值和新值,那么其他一些建议的解决方案可能更方便。
有很多方法可以查看多个值:
//angular 1.1.4
$scope.$watchCollection(['foo', 'bar'], function(newValues, oldValues){
// do what you want here
});
或更新版本
//angular 1.3
$scope.$watchGroup(['foo', 'bar'], function(newValues, oldValues, scope) {
//do what you want here
});
阅读官方文档了解更多信息:https : //docs.angularjs.org/api/ng/type/ $rootScope.Scope