Как просмотреть все изменения в области в AngularJS?
Angular $Функция часов позволяет запускать события при изменении указанного атрибута, как показано ниже. Есть ли аналогичный способ прослушивания событий, когда какие-либо изменения происходят в области?
// works
$scope.$watch("someval", function() { }, true);
$scope.$watch(function(scope){ return scope.someval; }, function() { }, true);
// doesn't work
$scope.$watch("this", function() { }, true);
$scope.$watch(function(scope){ return scope; }, function() { }, true);
Ответы
Ответ 1
Я считаю, что вы не можете следить за изменениями на $scope
(кроме использования @ValentynShybanov sugestion). Самое близкое, что вы можете сделать, это следить за вызовами дайджеста:
$scope.$watch(function() {
console.log("digest called");
});
Вышеуказанная функция будет вызываться каждый раз, когда в области видится $digest
, , даже если в свойствах области не было изменений.
Ответ 2
Это не просто, потому что область видимости - простой объект. Это Backbone, где вы можете подписаться на все события, но для этого ваши модели должны расширять собственный интерфейс - Backbone.Model
. Angular ставит в сторону шаблон наблюдателя в нем классический вид. Это необычное дизайнерское решение. В основном существует цикл, в котором Angular оценивает наблюдаемые выражения и когда обнаруживает отличие от предыдущей итерации, он уведомляет наблюдателей. Действительно интересный подход, вероятно, единственная альтернатива шаблону наблюдателя (за исключением, возможно, реактивного программирования, которое пока не распространено).
Я предлагаю использовать в качестве выражения watch функцию, которая возвращает хэш области. К сожалению, области содержат круговые ссылки где-то, поэтому быстрые решения, такие как JSON.stringify($scope)
, не работают. Я написал быстрое и грязное доказательство концепции. http://jsfiddle.net/ADukg/2544. Любое текстовое поле, которое вы вводите, печатает на консоли. Хеш-функция строки взята здесь Создает хэш из строки в Javascript/jQuery.
function MyCtrl($scope) {
$scope.$watch(
function($scope) {return hash($scope);},
function() {console.log("changed");}
);
}
Ответ 3
Я сам столкнулся с этой проблемой, и я решил ее с чем-то похожим на комментарий @ValentynShybanov, но не совсем то же самое. Мое решение не требует, чтобы вы префикс всех свойств, указанных в комментарии.
см. рабочий plunkr
var entireScope = {};
for ( var i in $scope ){
if ( i[0] !== '$' && i !== 'this' && i !== 'constructor'){
console.log(i);
entireScope[i] = $scope[i];
}
}
$scope.entireScope = entireScope;
$scope.$watch('entireScope', function( newValue, oldValue ){
$log.info('entireScope has changed',newValue, oldValue);
}, true);
поскольку вы видите, что решение совершенно одно и то же, но на самом деле оно добавляет другое свойство в область действия, а не заменяет структуру, которую у вас уже есть. это новое свойство представляет всю область действия (отсюда и ее название), и вы можете наблюдать за ней.
цикл, который я написал, может быть слишком общим, вы можете заменить его на персонализированную инициализацию. например:
$scope.entireScope = { 'someVal' : $scope.someVal }
это решение отвечает вашим потребностям и избавляет вас от необходимости реорганизовать код.
Ответ 4
Простое решение может заключаться в том, что вы должны проверять только переменную области, но это может быть и объект.
app.js
app.controller('MainController', ['$scope', function($scope){
$scope.watchable = {
'param1':'',
'param2':''
};
$scope.update = -1;
$scope.$watch('watchable', function(scope){
scope.update++;
}, true);
});
index.html
<div ng-controller="MainController">
<input type='text' ng-model="watchable.param1">
<input type='text' ng-model="watchable.param2">
<p>param1:{{watchable.param1}}, param2:{{watchable.param2}}</p>
<p>update:{{update}}
</div>
Трюк здесь состоит в том, чтобы передать "истину" в третьем параметре функции $watch, которая выполнит проверку angular.equal, которая проверяется по значению, а не простая контрольная проверка. Пожалуйста, дайте мне знать, если это правильно.