Comment puis-je déclencher une variable $watch
dans une directive Angular lors de la manipulation des données internes (par exemple, l'insertion ou la suppression de données), sans affecter un nouvel objet à cette variable?
J'ai un simple jeu de données en cours de chargement à partir d'un fichier JSON. Mon contrôleur Angular le fait, tout en définissant 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é la fonction $scope.add
et le nouvel objet est correctement inséré dans l'ensemble $scope.data
. Une table que j'ai configurée est mise à jour chaque fois que je clique 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 configurée pour surveiller $scope.data
n'est pas déclenchée lorsque tout cela se produit.
Je définis mon tag en HTML:
<d3-visualization val="data"></d3-visualization>
Qui est associé à la directive suivante (ajustée pour la santé 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 message "I see a data change!"
au tout début, mais jamais après en appuyant sur le bouton "ajouter".
Comment puis-je déclencher l'événement $watch
lorsque j'ajoute/supprime simplement des objets de l'objet data
, sans qu'un tout nouveau jeu de données soit affecté à l'objet data
?
Vous devez activer la vérification en profondeur de l'objet sale. Par défaut, angular ne vérifie que la référence de la variable de niveau supérieur que vous regardez.
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 Scope . Le troisième paramètre de la fonction $ watch active la vérification en profondeur si sa valeur est true.
Prenez note que la vérification en profondeur est coûteuse . Donc, si vous avez juste besoin de regarder le tableau d'enfants au lieu de la variable entière data
, observez la variable directement.
scope.$watch('val.children', function(newValue, oldValue) {}, true);
version 1.2.x introduite $ 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 mappes d'objets, cela implique de surveiller les propriétés).
scope.$watchCollection('val.children', function(newValue, oldValue) {});
Ma version pour 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));
}
});
}
});