I want to watch for changes in a dictionary, but for some reason watch callback is not called.
Here is a controller that I use:
function MyController($scope) {
$scope.form = {
name: 'my name',
surname: 'surname'
}
$scope.$watch('form', function(newVal, oldVal){
console.log('changed');
});
}
Here is fiddle.
I expect $watch callback to be fired each time name or surname is changed, but it doesn't happen.
What is the correct way to do it?
This question is related to
javascript
angularjs
angularjs-scope
you must changes in $watch ....
function MyController($scope) {_x000D_
$scope.form = {_x000D_
name: 'my name',_x000D_
}_x000D_
_x000D_
$scope.$watch('form.name', function(newVal, oldVal){_x000D_
console.log('changed');_x000D_
_x000D_
});_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>_x000D_
<div ng-app>_x000D_
<div ng-controller="MyController">_x000D_
<label>Name:</label> <input type="text" ng-model="form.name"/>_x000D_
_x000D_
<pre>_x000D_
{{ form }}_x000D_
</pre>_x000D_
</div>_x000D_
</div>
_x000D_
Little performance tip if somebody has a datastore kind of service with key -> value pairs:
If you have a service called dataStore, you can update a timestamp whenever your big data object changes. This way instead of deep watching the whole object, you are only watching a timestamp for change.
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();
}
});
And in a directive you are only watching the timestamp to change
app.directive("myDir", function ($scope, dataStore) {
$scope.dataStore = dataStore;
$scope.$watch('dataStore.getChange("myKey")', function(newVal, oldVal){
if(newVal !== oldVal && newVal){
// Data changed
}
});
});
For anyone that wants to watch for a change to an object within an array of objects, this seemed to work for me (as the other solutions on this page didn't):
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);
Try this:
function MyController($scope) {
$scope.form = {
name: 'my name',
surname: 'surname'
}
function track(newValue, oldValue, scope) {
console.log('changed');
};
$scope.$watch('form.name', track);
}
The reason why your code doesn't work is because $watch
by default does reference check. So in a nutshell it make sure that the object which is passed to it is new object. But in your case you are just modifying some property of form object not creating a new one. In order to make it work you can pass true
as the third parameter.
$scope.$watch('form', function(newVal, oldVal){
console.log('invoked');
}, true);
It will work but You can use $watchCollection which will be more efficient then $watch because $watchCollection
will watch for shallow properties on form object. E.g.
$scope.$watchCollection('form', function (newVal, oldVal) {
console.log(newVal, oldVal);
});
The form
object isn't changing, only the name
property is
updated fiddle
function MyController($scope) {
$scope.form = {
name: 'my name',
}
$scope.changeCount = 0;
$scope.$watch('form.name', function(newVal, oldVal){
console.log('changed');
$scope.changeCount++;
});
}
As you are looking for form object changes, the best watching approach is to use
$watchCollection
. Please have a look into official documentation for different performance characteristics.
Source: Stackoverflow.com