$ watchinging per la modifica dei dati in una direttiva angolare


132

Come posso attivare una $watchvariabile in una direttiva angolare durante la manipolazione dei dati all'interno (ad esempio, l'inserimento o la rimozione di dati), ma non assegnare un nuovo oggetto a quella variabile?

Ho un semplice set di dati attualmente caricato da un file JSON. Il mio controller angolare fa questo, oltre a definire alcune funzioni:

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

    };
});

Ho una funzione <button>che ha chiamato correttamente la $scope.addfunzione e il nuovo oggetto è correttamente inserito nel $scope.dataset. Una tabella che ho impostato si aggiorna ogni volta che premo il pulsante "Aggiungi".

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

Tuttavia, una direttiva che ho impostato per guardare $scope.datanon viene licenziata quando tutto ciò accade.

Definisco il mio tag in HTML:

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

Che è associato alla seguente direttiva (tagliato per sanità mentale della domanda):

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

Ricevo il "I see a data change!"messaggio all'inizio, ma mai dopo che premo il pulsante "aggiungi".

Come posso attivare l' $watchevento quando sto solo aggiungendo / rimuovendo oggetti datadall'oggetto, senza ottenere un set di dati completamente nuovo da assegnare dataall'oggetto?


5
Solo un breve suggerimento se newValue è sempre uguale a 0, false "" o qualsiasi altra cosa del genere "Vedo un cambiamento di dati!" non sparerà. Ad esempio, il valore originale era vero, newValue è falso. Dovrebbe essere sufficiente usare newValue lì dentro, quell'orologio viene chiamato solo se qualcosa è cambiato. Se è un oggetto, verrà chiamato all'istante.
Mathew Berg,

Un buon consiglio, grazie! Commuterò la ifdichiarazione.
Evil Closet Monkey,

Risposte:


218

È necessario abilitare il controllo sporco degli oggetti profondi. Per impostazione predefinita, angolare controlla solo il riferimento della variabile di livello superiore che si guarda.

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

vedi Scope . Il terzo parametro della funzione $ watch abilita il controllo deep dirty se è impostato su true.

Si noti che il controllo sporco profondo è costoso . Quindi, se hai solo bisogno di guardare l'array children invece dell'intera datavariabile, guarda direttamente la variabile.

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

la versione 1.2.x ha introdotto $ watchCollection

Shallow controlla le proprietà di un oggetto e si attiva ogni volta che una delle proprietà cambia (per gli array, ciò implica la visione degli oggetti dell'array; per le mappe degli oggetti, ciò implica la visione delle proprietà)

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

1
Funziona benissimo. Grazie!
Evil Closet Monkey,

1
Felice di aiutare. Continua a sperimentare con la funzione $ watch poiché le espressioni che può guardare sono piuttosto varie.
Liviu T.,

1
Grazie per aver notato come controllare solo array profondi;)
veritas

È un peccato che non posso votare più di una volta .. Ti darei una taglia, per la 2h che ho perso cercandolo.
Alex Arvanitidis,

migliore risposta là fuori.
Chovy

2

Perché se vuoi innescare i tuoi dati in profondità, devi passare il 3 ° argomento truedel tuo ascoltatore. Per impostazione predefinita è falsee significa che la tua funzione si innescherà, solo quando la tua variabile non cambierà campo .


1

La mia versione di una direttiva che utilizza jqplot per tracciare i dati non appena saranno disponibili:

    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));
                }
            });
        }
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.