Я хочу следить за изменениями в словаре, но почему-то вызов callback не вызывается.
Вот контроллер, который я использую:
function MyController($scope) {
$scope.form = {
name: 'my name',
surname: 'surname'
}
$scope.$watch('form', function(newVal, oldVal){
console.log('changed');
});
}
Вот скрипка: http://jsfiddle.net/Y8ByG/
Я ожидаю, что обратный вызов $watch будет срабатывать каждый раз, когда имя или фамилия будут изменены, но этого не произойдет.
Каков правильный способ сделать это?
Ответ 1
Вызовите $watch
с true
в качестве третьего аргумента:
$scope.$watch('form', function(newVal, oldVal){
console.log('changed');
}, true);
По умолчанию при сравнении двух сложных объектов в JavaScript они будут проверяться на "ссылочное" равенство, которое спрашивает, относятся ли эти два объекта к одной и той же вещи, а не к равенству "значение", которое проверяет, соответствуют ли значения всех свойств этих объекты равны.
В соответствии с Угловой документацией третий параметр предназначен для objectEquality
:
Когда objectEquality == true
, неравенство watchExpression определяется в соответствии с функцией angular.equals
. Чтобы сохранить значение объекта для последующего сравнения, angular.copy
функция angular.copy
. Это означает, что просмотр сложных объектов будет иметь неблагоприятные последствия для памяти и производительности.
Ответ 2
Объект form
не изменяется, только свойство name
обновленный скрипт: http://jsfiddle.net/ReuA8/1/
function MyController($scope) {
$scope.form = {
name: 'my name',
}
$scope.changeCount = 0;
$scope.$watch('form.name', function(newVal, oldVal){
console.log('changed');
$scope.changeCount++;
});
}
Ответ 3
Маленький показатель производительности, если у кого-то есть служба данных с хранилищем данных с парами ключ → значение:
Если у вас есть служба с именем dataStore, вы можете обновить временную метку, когда ваш большой объект данных изменится.
Таким образом, вместо глубокого просмотра всего объекта, вы просматриваете только временную метку изменений.
app.factory('dataStore', function () {
var store = { data: [], change: [] };
// when storing the data, updating the timestamp
store.setData = function(key, data){
store.data[key] = data;
store.setChange(key);
}
// get the change to watch
store.getChange = function(key){
return store.change[key];
}
// set the change
store.setChange = function(key){
store.change[key] = new Date().getTime();
}
});
И в директиве вы наблюдаете только временную метку, чтобы изменить
app.directive("myDir", function ($scope, dataStore) {
$scope.dataStore = dataStore;
$scope.$watch('dataStore.getChange("myKey")', function(newVal, oldVal){
if(newVal !== oldVal && newVal){
// Data changed
}
});
});
Ответ 4
Причина, по которой ваш код не работает, заключается в том, что $watch
по умолчанию выполняет проверку ссылок. Таким образом, в двух словах он гарантирует, что объект, который передается ему, является новым объектом. Но в вашем случае вы просто модифицируете некоторое свойство объекта формы, не создавая новое. Чтобы сделать это, вы можете передать true
в качестве третьего параметра.
$scope.$watch('form', function(newVal, oldVal){
console.log('invoked');
}, true);
Он будет работать, но вы можете использовать $watchCollection, который будет более эффективным, чем $watch, потому что $watchCollection
будет следить за неглубокими свойствами объекта формы. Например.
$scope.$watchCollection('form', function (newVal, oldVal) {
console.log(newVal, oldVal);
});
Ответ 5
Поскольку вы ищете изменения объекта формы, лучшим способом наблюдения является использование
$watchCollection
. Пожалуйста, ознакомьтесь с официальной документацией для разных характеристик производительности. https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch
Ответ 6
Попробуйте следующее:
function MyController($scope) {
$scope.form = {
name: 'my name',
surname: 'surname'
}
function track(newValue, oldValue, scope) {
console.log('changed');
};
$scope.$watch('form.name', track);
}
Ответ 7
Для тех, кто хочет следить за изменением объекта в массиве объектов, это, казалось, работает для меня (как это делали другие решения на этой странице):
function MyController($scope) {
$scope.array = [
data1: {
name: 'name',
surname: 'surname'
},
data2: {
name: 'name',
surname: 'surname'
},
]
$scope.$watch(function() {
return $scope.data,
function(newVal, oldVal){
console.log(newVal, oldVal);
}, true);
Ответ 8
вы должны внести изменения в $watch....
function MyController($scope) {
$scope.form = {
name: 'my name',
}
$scope.$watch('form.name', function(newVal, oldVal){
console.log('changed');
});
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app>
<div ng-controller="MyController">
<label>Name:</label> <input type="text" ng-model="form.name"/>
<pre>
{{ form }}
</pre>
</div>
</div>