132 votes

La surveillance des changements de données dans une directive Angular

Comment puis-je déclencher une $watch dans une directive Angular lors de la manipulation des données à l'intérieur (par exemple, l'insertion ou la suppression de données), mais ne pas assigner un nouvel objet à cette variable ?

J'ai un jeu de données simple qui est actuellement chargé à partir d'un fichier JSON. Mon contrôleur Angular s'en charge et définit quelques fonctions :

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

    };
});

J'ai un <button> qui a correctement appelé le $scope.add et le nouvel objet est correctement inséré dans le fichier $scope.data set. Un tableau que j'ai créé est mis à jour chaque fois que j'appuie sur le bouton "ajouter".

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

Cependant, une directive que j'ai mise en place pour surveiller les activités de l'Union européenne a été adoptée. $scope.data n'est pas licencié lorsque tout cela se produit.

Je définis ma balise en HTML :

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

qui est associée à la directive suivante (coupée pour des raisons de clarté de la question) :

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

Je reçois le "I see a data change!" au tout début, mais jamais après lorsque j'appuie sur le bouton "ajouter".

Comment puis-je déclencher le $watch alors que je ne fais qu'ajouter/supprimer des objets dans le fichier data et non d'obtenir un nouvel ensemble de données à affecter à l'objet data objet ?

219voto

Liviu T. Points 8894

Vous devez activer la vérification de la saleté des objets profonds. Par défaut, Angular ne vérifie que la référence de la variable de premier niveau que vous surveillez.

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

voir Champ d'application . Le troisième paramètre de la fonction $watch permet une vérification approfondie de la saleté s'il est fixé à true.

Il convient de noter que la vérification de la saleté profonde est coûteux . Ainsi, si vous avez besoin de surveiller uniquement le tableau des enfants au lieu de l'ensemble des data pour observer directement la variable.

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

introduction de la version 1.2.x $watchCollection

Shallow surveille les propriétés d'un objet et se déclenche chaque fois que l'une de ces propriétés change (pour les tableaux, cela implique de surveiller les éléments du tableau ; pour les cartes d'objets, cela implique de surveiller les propriétés).

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

2voto

Hazarapet Tunanyan Points 1458

Parce que si vous voulez déclencher vos données en profondeur, vous devez passer le troisième argument. true de votre auditeur. Par défaut, il s'agit de false et cela signifie que votre fonction ne se déclenchera que lorsque votre la variable changera et non son champ .

1voto

RobE Points 380

Ma version d'une directive qui utilise jqplot pour tracer les données une fois qu'elles sont disponibles :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X