私の範囲内のオブジェクトの配列があります、私は各オブジェクトのすべての値を見たいです。
これは私のコードです:
function TodoCtrl($scope) {
$scope.columns = [
{ field:'title', displayName: 'TITLE'},
{ field: 'content', displayName: 'CONTENT' }
];
$scope.$watch('columns', function(newVal) {
alert('columns changed');
});
}
しかし、値を変更すると、 TITLE
をTITLE2
に変更しましたが、alert('columns changed')
はポップされませんでした。
配列内のオブジェクトを詳細に監視する方法
ライブデモがあります: http://jsfiddle.net/SYx9b/ /
$watch
の3番目の引数をtrue
に設定できます。
$scope.$watch('data', function (newVal, oldVal) { /*...*/ }, true);
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch を参照してください。
Angular 1.1.x以降、$ watchCollectionを使用してコレクションの浅い監視(単に「最初のレベル」)を監視することもできます。
$scope.$watchCollection('data', function (newVal, oldVal) { /*...*/ });
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watchCollection を参照してください。
$ watchでオブジェクトを深く掘り下げると、パフォーマンスが低下します。時々(例えば、変更がプッシュとポップのみである場合)、array.lengthのような簡単に計算された値を$監視したいかもしれません。
1つの配列だけを見る場合は、このコードを使用することができます。
$scope.$watch('columns', function() {
// some value in the array has changed
}, true); // watching properties
しかし、これは複数の配列では動作しません。
$scope.$watch('columns + ANOTHER_ARRAY', function() {
// will never be called when things change in columns or ANOTHER_ARRAY
}, true);
この状況に対処するために、私は通常見たい複数の配列をJSONに変換します。
$scope.$watch(function() {
return angular.toJson([$scope.columns, $scope.ANOTHER_ARRAY, ... ]);
},
function() {
// some value in some array has changed
}
コメントで@jssebastianが指摘したように、JSON.stringify
はangular.toJson
よりも好まれるかもしれません。
Angular 1.1.x以降では、$ watchではなく $ watchCollection を使用できるようになりました。 $ watchCollectionは浅い時計を作成するように見えますが、あなたが期待するようなオブジェクトの配列では動作しません。配列への追加や削除は検出できますが、配列内のオブジェクトのプロパティは検出できません。
以下は、スコープ変数を見ることができる3つの方法と例を比較したものです。
$ watch() は、以下によって引き起こされます。
$scope.myArray = [];
$scope.myArray = null;
$scope.myArray = someOtherArray;
$ watchCollection() は上記のすべてによってトリガされます。
$scope.myArray.Push({}); // add element
$scope.myArray.splice(0, 1); // remove element
$scope.myArray[0] = {}; // assign index to different value
$ watch(...、true) は上記のすべてによってトリガされます。
$scope.myArray[0].someProperty = "someValue";
あと1つだけ...
$ watch() は、他の配列の内容がまったく同じであっても、その配列が別の配列に置き換えられたときにトリガーされる唯一のものです。
たとえば、$watch()
が起動し、$watchCollection()
が起動しない場合は、次のようになります。
$scope.myArray = ["Apples", "Bananas", "Orange" ];
var newArray = [];
newArray.Push("Apples");
newArray.Push("Bananas");
newArray.Push("Orange");
$scope.myArray = newArray;
以下はJSFiddleの例へのリンクです。この例では、さまざまなウォッチの組み合わせをすべて使用し、どの「ウォッチ」がトリガーされたかを示すログメッセージを出力します。
$ watchCollectionは、やりたいことを達成します。以下は、angularjsのWebサイトからコピーした例です http://docs.angularjs.org/api/ng/type/$rootScope.Scope 便利ですが、特にパフォーマンスを考慮する場合大規模なコレクションをご覧ください。
$scope.names = ['igor', 'matias', 'misko', 'james'];
$scope.dataCount = 4;
$scope.$watchCollection('names', function(newNames, oldNames) {
$scope.dataCount = newNames.length;
});
expect($scope.dataCount).toEqual(4);
$scope.$digest();
//still at 4 ... no changes
expect($scope.dataCount).toEqual(4);
$scope.names.pop();
$scope.$digest();
//now there's been a change
expect($scope.dataCount).toEqual(3);
私の場合は、他のいくつかのコントローラによって監視されているアドレスオブジェクトを含むサービスを監視する必要がありました。 'true'パラメータを追加するまでループし続けました。これは、オブジェクトを見ているときに成功するための鍵となるようです。
$scope.$watch(function() {
return LocationService.getAddress();
}, function(address) {
//handle address object
}, true);
この解決策は私にとって非常にうまくいった、私はディレクティブの中でこれをやっている。
$ watch(attrs.testWatch、function(){.....}、true);スコープ。
真実はかなりうまくいき、すべての変更に対して反応します(フィールドの追加、削除、または変更)。
これがそれで遊ぶための実用的なプランカーです。
これがあなたに役立つことを願っています。ご質問がありましたら、お気軽にお尋ねください。:)
$watch
関数のobjectEquality
パラメータ(3番目のパラメータ)を設定するのは、間違いなく配列のすべてのプロパティを監視する正しい方法です。
$scope.$watch('columns', function(newVal) {
alert('columns changed');
},true); // <- Right here
Piran はこれに十分に答え、$watchCollection
にも言及しています。
詳細
私がすでに答えられた質問に答えている理由は、私が wizardwerdna の答えは良いものではなく、使われるべきではないことを指摘したいからです。
問題は、ダイジェストがすぐには発生しないことです。実行前に現在のコードブロックが完了するまで待つ必要があります。したがって、配列のlength
を見ると、実際に$watchCollection
がキャッチする重要な変更がいくつか見逃される可能性があります。
この設定を仮定して下さい:
$scope.testArray = [
{val:1},
{val:2}
];
$scope.$watch('testArray.length', function(newLength, oldLength) {
console.log('length changed: ', oldLength, ' -> ', newLength);
});
$scope.$watchCollection('testArray', function(newArray) {
console.log('testArray changed');
});
一見すると、これらが同時に発砲するように見えるかもしれません。
function pushToArray() {
$scope.testArray.Push({val:3});
}
pushToArray();
// Console output
// length changed: 2 -> 3
// testArray changed
これは十分に機能しますが、これを考慮してください。
function spliceArray() {
// Starting at index 1, remove 1 item, then Push {val: 3}.
$testArray.splice(1, 1, {val: 3});
}
spliceArray();
// Console output
// testArray changed
配列に新しい要素があり、要素が失われた場合でも、結果の長さは同じであることに注意してください。$watch
については注意してください。length
は変更されていません。しかし、$watchCollection
が手に入れました。
function pushPopArray() {
$testArray.Push({val: 3});
$testArray.pop();
}
pushPopArray();
// Console output
// testArray change
同じ結果がプッシュとポップでも同じブロックで発生します。
結論
配列内のすべてのプロパティを監視するには、3番目のパラメータ(objectEquality)を含めて、配列自体に$watch
を使用し、trueに設定します。はい、これは高価ですが、時には必要です。
オブジェクトがいつ配列に出入りするかを見るには、$watchCollection
を使用します。
配列のlength
プロパティに$watch
を使用しないでください。私がそう考えることができるもっともな理由はほとんどありません。
$scope.changePass = function(data){
if(data.txtNewConfirmPassword !== data.txtNewPassword){
$scope.confirmStatus = true;
}else{
$scope.confirmStatus = false;
}
};
<form class="list" name="myForm">
<label class="item item-input">
<input type="password" placeholder="ใส่รหัสผ่านปัจจุบัน" ng-model="data.txtCurrentPassword" maxlength="5" required>
</label>
<label class="item item-input">
<input type="password" placeholder="ใส่รหัสผ่านใหม่" ng-model="data.txtNewPassword" maxlength="5" ng-minlength="5" name="checknawPassword" ng-change="changePass(data)" required>
</label>
<label class="item item-input">
<input type="password" placeholder="ใส่รหัสผ่านใหม่ให้ตรงกัน" ng-model="data.txtNewConfirmPassword" maxlength="5" ng-minlength="5" name="checkConfirmPassword" ng-change="changePass(data)" required>
</label>
<div class="spacer" style="width: 300px; height: 5px;"></div>
<span style="color:red" ng-show="myForm.checknawPassword.$error.minlength || myForm.checkConfirmPassword.$error.minlength">รหัสผ่านต้องมีจำนวน 5 หลัก</span><br>
<span ng-show="confirmStatus" style="color:red">รหัสผ่านใหม่ไม่ตรงกัน</span>
<br>
<button class="button button-positive button-block" ng-click="saveChangePass(data)" ng-disabled="myForm.$invalid || confirmStatus">เปลี่ยน</button>
</form>