Angularディレクティブのデータ変更を$ watchする


132

$watch内部でデータを操作(たとえば、データの挿入または削除)するときに、Angularディレクティブで変数をトリガーできますが、その変数に新しいオブジェクトを割り当てられません。

現在JSONファイルからロードされている単純なデータセットがあります。私のAngularコントローラーはこれを行い、いくつかの関数を定義します:

App.controller('AppCtrl', function AppCtrl($scope, JsonService) {
    // load the initial data model
    if (!$scope.data) {
        JsonService.getData(function(data) {
            $scope.data = data;
            $scope.records = data.children.length;
        });
    } else {
        console.log("I have data already... " + $scope.data);
    }

    // adds a resource to the 'data' object
    $scope.add = function() {
        $scope.data.children.push({ "name": "!Insert This!" });
    };

    // removes the resource from the 'data' object
    $scope.remove = function(resource) {
        console.log("I'm going to remove this!");
        console.log(resource);
    };

    $scope.highlight = function() {

    };
});

私は<button>それを適切に$scope.add関数と呼び、新しいオブジェクトは適切に$scope.dataセットに挿入されます。設定したテーブルは、[追加]ボタンをクリックするたびに更新されます。

<table class="table table-striped table-condensed">
  <tbody>
    <tr ng-repeat="child in data.children | filter:search | orderBy:'name'">
      <td><input type="checkbox"></td>
      <td>{{child.name}}</td>
      <td><button class="btn btn-small" ng-click="remove(child)" ng-mouseover="highlight()"><i class="icon-remove-sign"></i> remove</button></td>
    </tr>
  </tbody>
</table>

ただし、監視するように設定したディレクティブは、$scope.dataこれがすべて発生しても起動されません。

タグをHTMLで定義します。

<d3-visualization val="data"></d3-visualization>

これは、次のディレクティブに関連付けられています(質問の健全性のためにトリミングされています)。

App.directive('d3Visualization', function() {
    return {
        restrict: 'E',
        scope: {
            val: '='
        },
        link: function(scope, element, attrs) {
            scope.$watch('val', function(newValue, oldValue) {
                if (newValue)
                    console.log("I see a data change!");
            });
        }
    }
});

"I see a data change!"最初にメッセージが表示されますが、「追加」ボタンを押してもメッセージは表示されません。

まったく新しいデータセットを取得してオブジェクトに割り当てるのではなく$watchdataオブジェクトをオブジェクトに追加またはオブジェクトから削除しているときに、どうすればイベントをトリガーできdataますか?


5
newValueが0、false、 ""、または「データの変更がわかりました!」発砲しません。たとえば、元の値はtrue、newValueはfalseでした。その中でnewValueを使用するだけで十分なはずです。そのウォッチは、何かが変更された場合にのみ呼び出されます。オブジェクトの場合は、すぐに呼び出されます。
Mathew Berg

良いヒント、ありがとう!ifステートメントを切り替えます。
イービルクローゼットモンキー

回答:


218

ディープオブジェクトダーティチェックを有効にする必要があります。デフォルトでは、angularは監視している最上位の変数の参照のみをチェックします。

App.directive('d3Visualization', function() {
    return {
        restrict: 'E',
        scope: {
            val: '='
        },
        link: function(scope, element, attrs) {
            scope.$watch('val', function(newValue, oldValue) {
                if (newValue)
                    console.log("I see a data change!");
            }, true);
        }
    }
});

スコープを参照してください。$ watch関数の3番目のパラメーターは、trueに設定されている場合、ディープダーティーチェックを有効にします。

ディープダーティーチェックはコストかかることに注意してください。したがってdata、変数全体ではなく子配列を監視するだけの場合は、変数を直接監視します。

scope.$watch('val.children', function(newValue, oldValue) {}, true);

バージョン1.2.xは$ watchCollectionを導入しました

Shallowはオブジェクトのプロパティを監視し、プロパティのいずれかが変更されると起動します(配列の場合、これは配列項目を監視することを意味します。オブジェクトマップの場合、これはプロパティを監視することを意味します)

scope.$watchCollection('val.children', function(newValue, oldValue) {});

1
よく働く。ありがとうございました!
邪悪なクローゼットモンキー

1
お役に立ててうれしいです。監視できる式は非常に多様であるため、$ watch関数を試してください。
Liviu T.

1
深い配列のみをチェックする方法にご注意いただきありがとうございます;)
veritas

残念ながら、何度も投票することはできません。賞金を差し上げます。探していた2時間分を失ったからです。
Alex Arvanitidis 2015年

そこに最高の答え。
2015

2

データを深くトリガーしたい場合trueは、リスナーの3 false番目の引数を渡す必要があります。デフォルトでは、変数はフィールドではなく変更される場合にのみ、関数がトリガーされます


1

データが利用可能になったら、jqplotを使用してデータをプロットするディレクティブの私のバージョン:

    app.directive('lineChart', function() {
        $.jqplot.config.enablePlugins = true;

        return function(scope, element, attrs) {
            scope.$watch(attrs.lineChart, function(newValue, oldValue) {
                if (newValue) {
                    // alert(scope.$eval(attrs.lineChart));
                    var plot = $.jqplot(element[0].id, scope.$eval(attrs.lineChart), scope.$eval(attrs.options));
                }
            });
        }
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.