web-dev-qa-db-fra.com

$ regarder un objet

Je souhaite surveiller les modifications apportées à un dictionnaire, mais pour une raison quelconque, le rappel de surveillance n'est pas appelé.

Voici un contrôleur que j'utilise:

function MyController($scope) {
    $scope.form = {
        name: 'my name',
        surname: 'surname'
    }

    $scope.$watch('form', function(newVal, oldVal){
        console.log('changed');
    });
}

Voici violon .

Je m'attends à ce que $ watch callback soit déclenché à chaque changement de nom ou de nom de famille, mais cela ne se produit pas.

Quelle est la bonne façon de le faire?

307
Vladimir Sidorenko

Appelez $watch avec true comme troisième argument:

$scope.$watch('form', function(newVal, oldVal){
    console.log('changed');
}, true);

Par défaut, lors de la comparaison de deux objets complexes en JavaScript, l’égalité "référence" sera vérifiée, ce qui demande si les deux objets font référence à la même chose, plutôt que l’égalité "valeur", qui vérifie si les valeurs de toutes les objets sont égaux.

Selon la documentation Angular , le troisième paramètre est pour objectEquality:

Lorsque objectEquality == true, l'inégalité de watchExpression est déterminée conformément à la fonction angular.equals . Pour enregistrer la valeur de l'objet en vue d'une comparaison ultérieure, la fonction angular.copy est utilisée. Cela signifie donc que regarder des objets complexes aura des implications négatives sur la mémoire et les performances.

551
rossipedia

L'objet form ne change pas, seule la propriété name est

mis à jour violon

function MyController($scope) {
$scope.form = {
    name: 'my name',
}

$scope.changeCount = 0;
$scope.$watch('form.name', function(newVal, oldVal){
    console.log('changed');
    $scope.changeCount++;
});
}
13
Jason

Petit astuce performance si quelqu'un a un type de service de banque de données avec des paires clé -> valeur:

Si vous disposez d'un service appelé dataStore, vous pouvez mettre à jour un horodatage chaque fois que votre objet de données volumineuses change .

app.factory('dataStore', function () {

    var store = { data: [], change: [] };

    // when storing the data, updating the timestamp
    store.setData = function(key, data){
        store.data[key] = data;
        store.setChange(key);
    }

    // get the change to watch
    store.getChange = function(key){
        return store.change[key];
    }

    // set the change
    store.setChange = function(key){
        store.change[key] = new Date().getTime();
    }

});

Et dans une directive, vous ne faites que regarder l'horodatage pour changer

app.directive("myDir", function ($scope, dataStore) {
    $scope.dataStore = dataStore;
    $scope.$watch('dataStore.getChange("myKey")', function(newVal, oldVal){
        if(newVal !== oldVal && newVal){
            // Data changed
        }
    });
});
12
Ferenc Takacs

La raison pour laquelle votre code ne fonctionne pas est que $watch par défaut vérifie les références. Donc, en un mot, assurez-vous que l'objet qui lui est transmis est un nouvel objet. Mais dans votre cas, vous ne faites que modifier une propriété de l’objet formulaire qui n’en crée pas une nouvelle. Pour que cela fonctionne, vous pouvez passer true en tant que troisième paramètre.

$scope.$watch('form', function(newVal, oldVal){
    console.log('invoked');
}, true);

Cela fonctionnera, mais vous pouvez utiliser $ watchCollection qui sera plus efficace que $ watch car $watchCollection surveillera les propriétés superficielles de l’objet formulaire. Par exemple.

$scope.$watchCollection('form', function (newVal, oldVal) {
    console.log(newVal, oldVal);
});
4
sol4me

Lorsque vous recherchez des modifications d’objet de formulaire, la meilleure approche de contrôle consiste à utiliser
$watchCollection. Consultez la documentation officielle pour connaître différentes caractéristiques de performance.

4
Ramesh Papaganti

Essaye ça:

function MyController($scope) {
    $scope.form = {
        name: 'my name',
        surname: 'surname'
    }

    function track(newValue, oldValue, scope) {
        console.log('changed');
    };

    $scope.$watch('form.name', track);
}
1
Tarun

Pour quiconque souhaitait voir un changement d'objet dans un tableau d'objets, cela semblait fonctionner pour moi (contrairement aux autres solutions de cette page):

function MyController($scope) {

    $scope.array = [
        data1: {
            name: 'name',
            surname: 'surname'
        },
        data2: {
            name: 'name',
            surname: 'surname'
        },
    ]


    $scope.$watch(function() {
        return $scope.data,
    function(newVal, oldVal){
        console.log(newVal, oldVal);
    }, true);
0
Max