2013-05-24 7 views
76

Come moltiplicare le variabili $scope.$watch in Angolare e richiamare quando una di esse è stata modificata.Come guardare la modifica variabile multipla in angolare

$scope.name = ... 
$scope.age = ... 
$scope.$watch('???',function(){ 
    //called when name or age changed 
}) 
+0

C'è [un post di blog molto buono da Ben Nadel] (http://www.bennadel.com/blog/2566-Scope-watch-vs-watchCollection-In-AngularJS.htm) sull'argomento di $ watch vs $ watchCollection che potresti trovare utile. –

risposta

113

UPDATE

offerte angolari adesso i due metodi di ambito $watchGroup (dal 1,3) e $watchCollection. Quelli sono stati menzionati da @blazemonger e @kargold.


Questo dovrebbe funzionare indipendentemente dalle tipologie e valori:

$scope.$watch('[age,name]', function() { ... }, true); 

è necessario impostare il terzo parametro di vero in questo caso.

La concatenazione di stringhe 'age + name' fallirà in un caso come questo:

<button ng-init="age=42;name='foo'" ng-click="age=4;name='2foo'">click</button> 

Prima che l'utente fa clic sul pulsante il valore osservato sarebbe 42foo (42 + foo) e dopo il clic 42foo (4 + 2foo) . Quindi la funzione orologio non verrebbe chiamata. Quindi meglio usare un'espressione di array se non puoi garantire che tale caso non apparirà.

<!DOCTYPE html> 
<html> 
    <head> 
     <meta charset="UTF-8"> 
     <link href="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" rel="stylesheet" /> 
     <script src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script> 
     <script src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script> 
     <script src="http://code.angularjs.org/1.2.0-rc.2/angular.js"></script> 
     <script src="http://code.angularjs.org/1.2.0-rc.2/angular-mocks.js"></script> 
     <script> 

angular.module('demo', []).controller('MainCtrl', function ($scope) { 

    $scope.firstWatchFunctionCounter = 0; 
    $scope.secondWatchFunctionCounter = 0; 

    $scope.$watch('[age, name]', function() { $scope.firstWatchFunctionCounter++; }, true); 
    $scope.$watch('age + name', function() { $scope.secondWatchFunctionCounter++; }); 
}); 

describe('Demo module', function() { 
    beforeEach(module('demo')); 
    describe('MainCtrl', function() { 
     it('watch function should increment a counter', inject(function ($controller, $rootScope) { 
      var scope = $rootScope.$new(); 
      scope.age = 42; 
      scope.name = 'foo'; 
      var ctrl = $controller('MainCtrl', { '$scope': scope }); 
      scope.$digest(); 

      expect(scope.firstWatchFunctionCounter).toBe(1); 
      expect(scope.secondWatchFunctionCounter).toBe(1); 

      scope.age = 4; 
      scope.name = '2foo'; 
      scope.$digest(); 

      expect(scope.firstWatchFunctionCounter).toBe(2); 
      expect(scope.secondWatchFunctionCounter).toBe(2); // This will fail! 
     })); 
    }); 
}); 


(function() { 
    var jasmineEnv = jasmine.getEnv(); 
    var htmlReporter = new jasmine.HtmlReporter(); 
    jasmineEnv.addReporter(htmlReporter); 
    jasmineEnv.specFilter = function (spec) { 
     return htmlReporter.specFilter(spec); 
    }; 
    var currentWindowOnload = window.onload; 
    window.onload = function() { 
     if (currentWindowOnload) { 
      currentWindowOnload(); 
     } 
     execJasmine(); 
    }; 
    function execJasmine() { 
     jasmineEnv.execute(); 
    } 
})(); 

     </script> 
    </head> 
    <body></body> 
</html> 

http://plnkr.co/edit/2DwCOftQTltWFbEDiDlA?p=preview

PS:

Come indicato da @reblace in un commento, è naturalmente possibile accedere ai valori:

$scope.$watch('[age,name]', function (newValue, oldValue) { 
    var newAge = newValue[0]; 
    var newName = newValue[1]; 
    var oldAge = oldValue[0]; 
    var oldName = oldValue[1]; 
}, true); 
+0

Plunker non funzionante –

+0

@ Ajax3.14: cosa non funziona esattamente? Non riesco a riprodurre questo problema. Potrebbe essere che vedi l'uscita jasmie "Failing 1 spec"? Questo sarebbe l'output previsto, perché il test fallisce (vedi il commento nel codice sorgente del test). – stofl

+1

Questa risposta mi ha aiutato, grazie! La bellezza di questo approccio è che puoi accedere a newValue/oldValue come elementi dell'array visto (ad esempio newValue [0], newValue [1] e oldValue [0], oldValue [1]) – reblace

43
$scope.$watch('age + name', function() { 
    //called when name or age changed 
}); 
+2

Questo funzionerà a causa di JS che li concentra come stringhe. Buona risposta e quella giusta tra. – Heinrich

+3

A qualcuno che trova risposta alla stessa domanda - la mia risposta è errata, questa risposta è quella giusta. – callmekatootie

+4

Assicurati anche che in questo caso non usi gli argomenti 'newValue' e' oldValue' che l'angolare passa al callback perché saranno la concatenazione risultante e non solo il campo che è stato modificato. –

6

ci sono molti modo per guardare più valori:

//angular 1.1.4 
$scope.$watchCollection(['foo', 'bar'], function(newValues, oldValues){ 
    // do what you want here 
}); 

o più recente versione

//angular 1.3 
$scope.$watchGroup(['foo', 'bar'], function(newValues, oldValues, scope) { 
    //do what you want here 
}); 

Leggi doc ufficiale per maggiori informazioni: https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope

+1

Perché questo è stato rifiutato? Cosa c'è di sbagliato in questo? – MGot90

+0

Credo che 'watchCollection' debba essere una stringa. Ho intenzione di confermare quindi modificare. – KthProg

+0

Vale anche la pena ricordare che credo che i nuovi e vecchi valori siano accessibili in diversi modi tra queste funzioni. – KthProg

5

Nessuno ha menzionato l'ovvio:

var myCallback = function() { console.log("name or age changed"); }; 
$scope.$watch("name", myCallback); 
$scope.$watch("age", myCallback); 

Ciò potrebbe significare un po 'meno di polling. Se guardi sia name + age (per questo) sia name (altrove), suppongo che Angular guarderà efficacemente a name due volte per vedere se è sporco.

È discutibilmente più leggibile utilizzare la callback per nome invece di evidenziarlo. Soprattutto se puoi dare un nome migliore rispetto al mio esempio.

E si può guardare i valori in modo diverso se è necessario:

$scope.$watch("buyers", myCallback, true); 
$scope.$watchCollection("sellers", myCallback); 

$watchGroup è bello se si può usare, ma per quanto posso dire, non ti permettono di vedere il membri del gruppo come raccolta o con uguaglianza di oggetti.

Se sono necessari i valori vecchi e nuovi di entrambe le espressioni all'interno di una stessa chiamata di funzione di richiamata, allora forse alcune delle altre soluzioni proposte sono più convenienti.

+0

chiama la funzione di callback anche per la prima volta quando viene caricato il mio controller? non posso smettere di chiamare per la prima volta quando viene caricato il controller? –

Problemi correlati