3

フィドル

リストがあり、それが変更されるたびに通知を受けたいです。単純な$watch式が機能していません。これは、angular が構造上の等価性ではなく、参照の等価性をチェックしているためだと推測しています。

<html ng-app>
    <head>
    </head>
    <body ng-controller="Root">
        <h1>Base Angular Fiddle</h1>
        Times changed: {{timesChanged}}
        <ul>
            <li ng-repeat="name in names">{{name}}</li>
            <li><button ng-click="names.push('another name')">Add</button></li>
        </ul>
    </body>
</html>
​

​function Root($scope) {
    $scope.timesChanged = 0;
    $scope.names = ['foo', 'bar', 'baz'];
    $scope.$watch('names', function() {
        $scope.timesChanged++;
    });
}​

私が期待しているのは'names'、 を呼び出すたびに のコールバックが呼び出されることですnames.push()。これに対して推奨される回避策はありますか? それとも、$watch正しく使用していないだけですか?

4

2 に答える 2

9

そうです、パフォーマンス上の理由から、デフォルトで参照用のAngularチェックが行われます。docs でわかるように、参照と等価の使用法は $watch 関数の 3 番目の引数の値に依存します。true (デフォルトでは false) に設定するだけで、フィドルが機能します

変化:

$scope.$watch('names', function() {
        $scope.timesChanged++;
    }, true);

編集 - パフォーマンスへの影響:

変数のサイズと複雑さによっては、2 つの配列/オブジェクトを比較することは明らかに非常に非効率的です (したがって、参照角度によるチェックはデフォルトで行われます)。別の方法があります - 配列の長さを監視します。これには明らかな制限があります。1 つの要素を変更しても $watch 関数はトリガーされなくなりますが、非常に高速になる可能性があります。これが更新されたフィドルです!

于 2012-12-11T23:05:23.233 に答える
1

ちょっとした追加:

より特別なことを監視したい場合は、次のようにできます。

$scope.$watch(function() {
    // Define what you are watching for
    // For example convert your array into a string
    return String($scope.names);
}, function(newValue, oldValue) {
    // Do something cool.
});

これは間違いなくそれほど速くはありませんが、いろいろnames.length試してみると洗練されたソリューションを見つけることができます。

誰かが興味を持っている場合は、変更された Duff のデバイスを使用する高速ハッシュで少し遊んでみました: http://jsfiddle.net/flek/mfKT6/1/大量のデータを扱っている場合、このハッシュ方法も更新されてエラーになる可能性があります。レスポンシブ (2 文字目または 3 文字ごとにのみハッシュするなど)

于 2012-12-13T20:58:32.567 に答える