wake-up-neo.com

$ watch'ing for data changes in einer Angular Direktive

Wie kann ich eine Variable $watch In einer Direktive Angular) auslösen, wenn ich die Daten darin bearbeite (z. B. Daten einfügen oder entfernen), aber dieser Variablen kein neues Objekt zuweisen?

Ich habe einen einfachen Datensatz, der gerade aus einer JSON-Datei geladen wird. Mein Angular Controller tut dies und definiert ein paar Funktionen:

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() {

    };
});

Ich besitze einen <button>, Der die Funktion $scope.add Ordnungsgemäß aufruft, und das neue Objekt wird ordnungsgemäß in den Satz $scope.data Eingefügt. Eine Tabelle, die ich erstellt habe, wird jedes Mal aktualisiert, wenn ich auf die Schaltfläche "Hinzufügen" klicke.

<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>

Eine Direktive, die ich eingerichtet habe, um $scope.data Zu beobachten, wird jedoch nicht ausgelöst, wenn dies alles passiert.

Ich definiere mein Tag in HTML:

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

Womit die folgende Richtlinie in Verbindung gebracht wird (aus Gründen der Vernunft der Fragen):

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!");
            });
        }
    }
});

Ich erhalte ganz am Anfang die Meldung "I see a data change!", Aber niemals danach, wenn ich auf die Schaltfläche "Hinzufügen" drücke.

Wie kann ich das Ereignis $watch Auslösen, wenn ich gerade Objekte zum Objekt data hinzufüge/daraus entferne und dem Objekt data kein ganz neues Dataset zuzuweisen habe?

132

Sie müssen die Deep Object Dirty-Prüfung aktivieren. Standardmäßig überprüft angular nur die Referenz der Variablen der obersten Ebene, die Sie beobachten.

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);
        }
    }
});

siehe Scope . Der dritte Parameter der $ watch-Funktion aktiviert die Deep-Dirty-Prüfung, wenn er auf true gesetzt ist.

Beachten Sie, dass eine gründliche Verschmutzungsprüfung teuer ist . Wenn Sie also nur das untergeordnete Array anstelle der gesamten Variablen data überwachen müssen, wird die Variable direkt überwacht.

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

version 1.2.x eingeführt $ watchCollection

Shallow überwacht die Eigenschaften eines Objekts und wird immer dann ausgelöst, wenn sich eine der Eigenschaften ändert.

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

Denn wenn Sie Ihre Daten mit deep of it auslösen wollen, müssen Sie das 3. Argument true Ihres Listeners übergeben. Standardmäßig ist es false und es bedeutet, dass Ihre Funktion nur ausgelöst wird, wenn Ihre Variable ändert nicht das Feld.

2

Meine Version für eine Direktive, die jqplot verwendet, um die Daten zu zeichnen, sobald sie verfügbar sind:

    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));
                }
            });
        }
});
1
RobE