Como posso acionar uma variável $watch
em uma diretiva Angular ao manipular os dados dentro (por exemplo, inserir ou remover dados), mas não atribuir um novo object a essa variável?
Eu tenho um dataset simples atualmente sendo carregado a partir de um arquivo JSON. Meu controlador Angular faz isso, assim como define algumas funções:
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() { }; });
Eu tenho um que corretamente chamado a function
$scope.add
, e o novo object é inserido corretamente no conjunto $scope.data
. Uma tabela que eu configurei atualiza cada vez que eu clico no botão “Adicionar”.
{{child.name}}
No entanto, uma diretiva que configurei para assistir a $scope.data
não está sendo triggersda quando tudo isso acontece.
Eu defino minha tag em HTML:
Que está associado à seguinte diretiva (aparada para sanidade de pergunta):
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!"); }); } } });
Eu recebo o "I see a data change!"
mensagem no início, mas nunca depois que eu apertar o botão “Adicionar”.
Como posso acionar o evento $watch
quando estou apenas adicionando / removendo objects do object de data
, não obtendo um dataset totalmente novo para atribuir ao object de data
?
Você precisa ativar a verificação de objects profundos. Por padrão, o padrão angular só verifica a referência da variável de nível superior que você assiste.
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); } } });
veja Escopo . O terceiro parâmetro da function $ watch permite uma verificação profunda e suja se estiver definida como verdadeira.
Tome nota que a verificação profunda e suja é cara . Então, se você só precisa observar a matriz de filhos em vez da variável de data
inteira, observe a variável diretamente.
scope.$watch('val.children', function(newValue, oldValue) {}, true);
versão 1.2.x introduzida $ watchCollection
Raso assiste as propriedades de um object e é acionado sempre que qualquer uma das propriedades é alterada (para matrizes, isso significa observar os itens da matriz; para mapas de objects, isso significa observar as propriedades)
scope.$watchCollection('val.children', function(newValue, oldValue) {});
Minha versão para uma diretiva que usa o jqplot para plotar os dados assim que ele estiver disponível:
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)); } }); } });
Porque se você quer acionar seus dados com profundidade, você tem que passar o 3o argumento true
de seu ouvinte. Por padrão, é false
e o que você funciona irá triggersr, somente quando sua variável vai mudar e não o campo .