$ assistir a um object

Quero observar as alterações em um dictionary, mas, por algum motivo, o retorno de chamada do relógio não é chamado.

Aqui está um controlador que eu uso:

function MyController($scope) { $scope.form = { name: 'my name', surname: 'surname' } $scope.$watch('form', function(newVal, oldVal){ console.log('changed'); }); } 

Aqui está o violino: http://jsfiddle.net/Y8ByG/

Espero que o retorno de chamada $ watch seja acionado sempre que o nome ou sobrenome for alterado, mas isso não acontece.

Qual é a maneira correta de fazer isso?

Chame $watch com true como o terceiro argumento:

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

Por padrão, ao comparar dois objects complexos em JavaScript, eles serão verificados quanto à igualdade de “referência”, que pergunta se os dois objects se referem à mesma coisa, em vez da igualdade “valor”, que verifica se os valores de todas as propriedades daqueles objects são iguais.

De acordo com a documentação do Angular , o terceiro parâmetro é para objectEquality :

Quando objectEquality == true , a desigualdade do watchExpression é determinada de acordo com a function angular.equals . Para salvar o valor do object para comparação posterior, a function angular.copy é usada. Isso significa, portanto, que observar objects complexos terá implicações adversas de memory e desempenho.

O object de form não está mudando, apenas a propriedade name é

violino atualizado: http://jsfiddle.net/ReuA8/1/

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

Pouca dica de desempenho se alguém tiver um tipo de serviço de armazenamento de dados com pares de chave -> valor:

Se você tiver um serviço chamado dataStore , poderá atualizar um registro de data e hora sempre que o object de dados grandes for alterado. Desta forma, em vez de observar profundamente o object inteiro, você está apenas observando um timestamp para a mudança.

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

E em uma diretiva você está apenas observando o timestamp para mudar

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

A razão pela qual seu código não funciona é porque $watch por padrão faz a verificação de referência. Então, em poucas palavras, certifique-se de que o object que é passado para ele é um novo object. Mas no seu caso você está apenas modificando alguma propriedade do object de formulário não criando um novo object. Para que isso funcione, você pode passar true como o terceiro parâmetro.

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

Ele funcionará, mas você pode usar o $ watchCollection, que será mais eficiente do que o $ watch, porque o $watchCollection observará as propriedades superficiais no object de formulário. Por exemplo

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

Como você está procurando por mudanças no object de formulário, a melhor abordagem de observação é usar
$watchCollection . Por favor, olhe para documentação oficial para diferentes características de desempenho. https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch

Tente isto:

 function MyController($scope) { $scope.form = { name: 'my name', surname: 'surname' } function track(newValue, oldValue, scope) { console.log('changed'); }; $scope.$watch('form.name', track); } 

Para qualquer pessoa que queira observar uma alteração em um object dentro de uma matriz de objects, isso pareceu funcionar para mim (como as outras soluções desta página não funcionaram):

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

você deve mudar em $ watch ….

 function MyController($scope) { $scope.form = { name: 'my name', } $scope.$watch('form.name', function(newVal, oldVal){ console.log('changed'); }); } 
  
 {{ form }}