Как $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
})
UPDATE
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
). Таким образом, функция часов не будет вызвана. Поэтому лучше использовать выражение массива, если вы не можете гарантировать, что такой случай не появится.
<!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 для массива выражений. Мне это нравится, потому что это делает намерение более ясным в коде.
Существует много способов просмотра нескольких значений:
//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
Никто не упомянул очевидное:
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
приятно, если вы можете использовать его, но, насколько я могу судить, он не позволяет вам наблюдать за членами группы как с коллекцией или с равенством объектов.
Если вам нужны старые и новые значения обоих выражений внутри одного и того же вызова функции обратного вызова, то, возможно, некоторые из других предлагаемых решений более удобны.