辞書の変更を監視したいのですが、何らかの理由でwatch callbackが呼び出されません。
これが私が使うコントローラーです:
function MyController($scope) {
$scope.form = {
name: 'my name',
surname: 'surname'
}
$scope.$watch('form', function(newVal, oldVal){
console.log('changed');
});
}
これは フィドル です。
名前または姓が変更されるたびに$ watchコールバックが起動されると思いますが、発生しません。
それをする正しい方法は何ですか?
3番目の引数としてtrue
を指定して$watch
を呼び出します。
$scope.$watch('form', function(newVal, oldVal){
console.log('changed');
}, true);
デフォルトでは、JavaScriptで2つの複雑なオブジェクトを比較するときに、それらがすべてのプロパティの値をチェックする「値」の同等性ではなく、「参照」同等性がチェックされます。オブジェクトは等しい.
Angular documentation によると、3番目のパラメータはobjectEquality
です。
objectEquality == true
の場合、watchExpressionの不等式はangular.equals
関数に従って決定されます。後で比較できるようにオブジェクトの値を保存するには、angular.copy
関数を使用します。したがって、これは複雑なオブジェクトを見ていると、メモリとパフォーマンスに悪影響があることを意味します。
form
オブジェクトは変更されていません。name
プロパティのみが変更されています。
更新された フィドル
function MyController($scope) {
$scope.form = {
name: 'my name',
}
$scope.changeCount = 0;
$scope.$watch('form.name', function(newVal, oldVal){
console.log('changed');
$scope.changeCount++;
});
}
少し パフォーマンスのヒント 誰かがキー - >値のペアでデータストアのようなサービスを受けている場合:
dataStore というサービスがある場合は、ビッグデータオブジェクトが変更されたときはいつでも timestamp を更新できます。この方法では、オブジェクト全体を詳細に監視するのではなく、変更のタイムスタンプを監視するだけです。
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
}
});
});
あなたのコードが機能しない理由は、デフォルトで$watch
が参照チェックをするからです。一言で言えば、それに渡されるオブジェクトが新しいオブジェクトであることを確認してください。しかしあなたの場合は、フォームオブジェクトのいくつかのプロパティを変更するだけで、新しいプロパティは作成されません。それを機能させるためには、3番目のパラメータとしてtrue
を渡すことができます。
$scope.$watch('form', function(newVal, oldVal){
console.log('invoked');
}, true);
$watchCollection
はフォームオブジェクトの浅いプロパティを監視するので、これは動作しますが、$ watchよりも効率的な$ watchCollectionを使用できます。例えば。
$scope.$watchCollection('form', function (newVal, oldVal) {
console.log(newVal, oldVal);
});
フォームオブジェクトの変更を探しているのであれば、最も効果的な方法はを使用することです。$watchCollection
。さまざまなパフォーマンス特性については、公式の ドキュメント をご覧ください。
これを試して:
function MyController($scope) {
$scope.form = {
name: 'my name',
surname: 'surname'
}
function track(newValue, oldValue, scope) {
console.log('changed');
};
$scope.$watch('form.name', track);
}
オブジェクトの配列内のオブジェクトへの変更を監視したい人のために、これは私のために働くように見えた(このページの他の解決策はしなかったように):
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);