web-dev-qa-db-ja.com

変数を監視して変更する

AngularJSには、スコープ変数を監視するディレクティブがあります。変数に特定のデータが含まれている場合、その変数を少し変更する必要があります。問題は、変数を変更すると$watchが再びトリガーされます。だから私は連続ループになってしまいます。

scope.$watch('someVar', function(newValue, oldValue) {
    console.log(newValue);
    scope.someVar = [Do something with someVar];
});

これにより、$watch再び、これは理にかなっています。しかし、監視対象の変数を変更する方法が必要です。これを行う方法はありますか?

20
Vivendi

_$scope.$watch_を使用して変数の変更を監視する場合、angularは参照が変更されたかどうかを確認します。変更された場合、ビューを更新するために_$watch_ハンドラーが実行されます。

$ watchハンドラー内でスコープ変数を変更する場合、スコープ変数参照は呼び出されるたびに変わるため、無限の$ digestループがトリガーされます。

無限ダイジェストの問題を回避するためのコツは、angle.copydocs )を使用して_$watch_ハンドラー内の参照をpreserveすることです。 :

_scope.$watch('someVar', function(newValue, oldValue) {
    console.log(newValue);
    var someVar = [Do something with someVar];

    // angular copy will preserve the reference of $scope.someVar
    // so it will not trigger another digest 
    angular.copy(someVar, $scope.someVar);

});
_

注:このトリックは、オブジェクト参照に対してのみ機能します。プリミティブでは機能しません。

一般的に、独自の_$watched_リスナー内で_$watch_変数を更新することはお勧めできません。ただし、避けられない場合もあります。

26
pixelbits

関数内でif条件を使用して、連続forループを回避します

scope.$watch('someVar', function(newValue, oldValue) {
   if(newValue!==oldValue) {
    console.log(newValue);
    scope.someVar = [Do something with someVar];
   } 
});
13
chandu

これがダーティチェックの仕組みです。 $scopeの何かが変更されるたびにAngularはスコープにアタッチされているすべてのものをスピンし、それ以上変更がなくなるまでそうし続けます。

そのようなことをしたい場合は、$watch関数がべき等であることを確認する必要があります。 newValueoldValueの両方を見て、この$digestループで既に変数に変更を適用したかどうかを把握する必要があります。それを行う方法は、someVarに対してどのような変更を行っているかによって多少異なります。

一般的に、ウォッチ関数でウォッチ変数を変更することは残念ながら良い考えではありません。

2
ivarni

bool変数を使用して管理できます

$scope.someVarChanged = false;

scope.$watch('someVar', function(newValue, oldValue) {
    console.log(newValue);
    $scope.someVarChanged = !$scope.someVarChanged!;
    if($scope.someVarChanged) {            
        scope.someVar = [Do something with someVar];
    }
});
2
harishr

はい、このようにキャンセルできます

var wathcer = scope.$watch('someVar', function(newValue, oldValue) {
    console.log(newValue);
    scope.someVar = [Do something with someVar];

});
wathcer(); // clear the watch
1