Obejrzyj wiele atrybutów $ scope


Odpowiedzi:


586

Począwszy od AngularJS 1.3 istnieje nowa metoda wywołana $watchGroupdo obserwowania zestawu wyrażeń.

$scope.foo = 'foo';
$scope.bar = 'bar';

$scope.$watchGroup(['foo', 'bar'], function(newValues, oldValues, scope) {
  // newValues array contains the current values of the watch expressions
  // with the indexes matching those of the watchExpression array
  // i.e.
  // newValues[0] -> $scope.foo 
  // and 
  // newValues[1] -> $scope.bar 
});

7
jaka jest różnica w stosunku do $ watchCollection ('[a, b]') ??
Kamil Tomšík

28
Różnica polega na tym, że można użyć odpowiedniej tablicy zamiast ciągu, który wygląda jak tablica
Paolo Moretti

2
Miałem podobny problem, ale używałem wzorca ControllerAs. W moim przypadku poprawka polegała na dodaniu do zmiennych nazwy kontrolera:$scope.$watchGroup(['mycustomctrl.foo', 'mycustomctrl.bar'],...
morels

1
To nie wydaje mi się działać w Angular 1.6. Jeśli włączę dziennik konsoli do funkcji, widzę, że działa ona tylko raz za pomocą newValuesi oldValuesas undefined, podczas indywidualnego oglądania właściwości działają jak zwykle.
Alejandro García Iglesias

290

Począwszy od AngularJS 1.1.4 możesz używać $watchCollection:

$scope.$watchCollection('[item1, item2]', function(newValues, oldValues){
    // do stuff here
    // newValues and oldValues contain the new and respectively old value
    // of the observed collection array
});

Przykład plunkera tutaj

Dokumentacja tutaj


109
Zauważ, że pierwszy parametr nie jest tablicą. To ciąg, który wygląda jak tablica.
MK Safi

1
dzięki za to. jeśli to zadziała, dam ci tysiąc złotych monet - oczywiście wirtualnych :)
AdityaSaxena

5
Wyjaśnienie (zajęło mi kilka minut uświadomienie sobie) $watchCollectionma na celu przekazanie obiektu i obserwowanie zmian w dowolnych właściwościach obiektu, podczas gdy w $watchGroupzamierzeniu ma być przekazany szereg indywidualnych właściwości do obserwowania zmian. Nieco inaczej, aby rozwiązać podobne, ale różne problemy. Uff!
Mattygabe

1
Jakoś nowe wartości i stare wartości są zawsze równe, gdy używasz tej metody: plnkr.co/edit/SwwdpQcNf78pQ80hhXMr
mostruash

Dzięki. To rozwiązało mój problem. Czy jest jakiś błąd w wydajności / problem z używaniem $ watch?
Syed Nasir Abbas

118

$watch Pierwszy parametr może być również funkcją.

$scope.$watch(function watchBothItems() {
  return itemsCombinedValue();
}, function whenItemsChange() {
  //stuff
});

Jeśli dwie połączone wartości są proste, pierwszy parametr jest normalnie wyrażeniem kątowym. Na przykład firstName i lastName:

$scope.$watch('firstName + lastName', function() {
  //stuff
});

8
Wygląda to na przypadek użycia, który domyślnie woła o włączenie do frameworka. Nawet obliczona własność tak prosta, jak fullName = firstName + " " + lastNamewymaga przekazania funkcji jako pierwszego argumentu (zamiast prostego wyrażenia, takiego jak 'firstName, lastName'). Angular jest tak potężny, ale jest kilka obszarów, w których może być niezwykle przyjazny dla programistów w sposób, który (nie wydaje się) narażać na szwank wydajności lub zasad projektowania.
XML

4
No cóż, $ watch po prostu przyjmuje wyraz kątowy, który jest oceniany w zakresie, w jakim jest wywoływany. Więc możesz to zrobić $scope.$watch('firstName + lastName', function() {...}). Można też po prostu zrobić dwa zegarki: function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged);. Do odpowiedzi dodałem prosty przypadek.
Andrew Joslin

Plus w „firstName + lastName” to konkatenacja łańcuchów. Zatem kątowy sprawdza tylko, czy wynik konkatenacji jest teraz inny.
mb21

16
Łączenie łańcuchów wymaga nieco uwagi - jeśli zmienisz „paran orman” na „para norman”, nie wywołasz odpowiedzi; najlepiej umieścić dzielnik, taki jak „\ t | \ t” między pierwszym i drugim
semestrem

chociaż Amberjs jest do bani, ale ma tę wbudowaną funkcję! słyszę tych kanciastych facetów. Myślę, że robienie zegarków jest najbardziej racjonalnym wykonalnym sposobem.
Aladdin Mhemed

70

Oto rozwiązanie bardzo podobne do oryginalnego pseudokodu, które faktycznie działa:

$scope.$watch('[item1, item2] | json', function () { });

EDYCJA: OK, myślę, że jest jeszcze lepiej:

$scope.$watch('[item1, item2]', function () { }, true);

Zasadniczo pomijamy krok Jsona, co na początku wydawało się głupie, ale bez niego nie działałoby. Klucz to często pomijany trzeci parametr, który włącza równość obiektów w przeciwieństwie do równości odniesienia. Wtedy porównania między naszymi utworzonymi obiektami tablicowymi faktycznie działają poprawnie.


Miałem podobne pytanie. I to jest dla mnie poprawna odpowiedź.
Calvin Cheng

Oba mają niewielki narzut wydajności, jeśli elementy w wyrażeniu tablicowym nie są typami prostymi.
null

To prawda… dokonuje pełnego porównania obiektów składowych. Który może, ale nie musi, być tym, czego chcesz. Zobacz aktualnie zatwierdzoną odpowiedź dla wersji z nowoczesnym kątem, która nie wykonuje pełnego porównania głębokości.
Karen Zilles

Z jakiegoś powodu, gdy próbowałem użyć $ watchCollection na tablicy, dostałem ten błąd, TypeError: Object #<Object> has no method '$watchCollection'ale to rozwiązanie pomaga mi rozwiązać mój problem!
abottoni

Fajnie, możesz nawet oglądać wartości w obiektach:$scope.$watch('[chaptercontent.Id, anchorid]', function (newValues, oldValues) { ... }, true);
Serge van den Oever

15

Możesz użyć funkcji w $ watchGroup, aby wybrać pola obiektu w zakresie.

        $scope.$watchGroup(
        [function () { return _this.$scope.ViewModel.Monitor1Scale; },   
         function () { return _this.$scope.ViewModel.Monitor2Scale; }],  
         function (newVal, oldVal, scope) 
         {
             if (newVal != oldVal) {
                 _this.updateMonitorScales();
             }
         });

1
Dlaczego używacie _this? Czy zakres nie jest przenoszony do funkcji bez wyraźnego zdefiniowania go?
sg.cc

1
Używam maszynopisu, prezentowany kod jest skompilowanym wynikiem.
Yang Zhang

12

Dlaczego nie po prostu owinąć to w forEach?

angular.forEach(['a', 'b', 'c'], function (key) {
  scope.$watch(key, function (v) {
    changed();
  });
});

To mniej więcej tyle samo, co zapewnienie funkcji dla połączonej wartości, bez faktycznego martwienia się o skład wartości .


W takim przypadku log () byłby wykonywany kilka razy, prawda? Myślę, że w przypadku zagnieżdżonych funkcji $ watch nie byłoby. I nie powinno w rozwiązaniu oglądać kilku atrybutów jednocześnie.
John Doe

Nie, dziennik jest wykonywany tylko raz na zmianę dla obserwowanej właściwości. Dlaczego miałby być wywoływany wiele razy?
Erik Aigner

Racja, mam na myśli, że nie działałoby to dobrze, gdybyśmy chcieli oglądać je wszystkie jednocześnie.
John Doe

1
Jasne, czemu nie? Robię to w mój projekt. changed()jest wywoływany za każdym razem, gdy coś zmienia się w którejkolwiek z właściwości. To jest dokładnie to samo zachowanie, jakby podano funkcję dla połączonej wartości.
Erik Aigner

1
Różni się to nieco tym, że jeśli wiele elementów w tablicy zmienia się w tym samym czasie, zegarek $ uruchomi obsługę tylko raz zamiast raz na zmianę elementu.
bingles

11

Nieco bezpieczniejszym rozwiązaniem łączenia wartości może być użycie następujących $watchfunkcji:

function() { return angular.toJson([item1, item2]) }

lub

$scope.$watch(
  function() {
    return angular.toJson([item1, item2]);
  },
  function() {
    // Stuff to do after either value changes
  });

5

Pierwszy parametr $ watch może być wyrażeniem kątowym lub funkcją. Zobacz dokumentację dotyczącą $ scope. $ Watch . Zawiera wiele użytecznych informacji o tym, jak działa metoda $ watch: kiedy wywoływana jest funkcja watchExpression, sposób porównywania wyników przez kąt itp.


4

Co powiesz na:

scope.$watch(function() { 
   return { 
      a: thing-one, 
      b: thing-two, 
      c: red-fish, 
      d: blue-fish 
   }; 
}, listener...);

2
Bez trzeciego trueparametru to scope.$watch(jak w twoim przykładzie) listener()uruchamiany byłby za każdym razem, ponieważ anonimowy skrót ma za każdym razem inne odniesienie.
Peter V. Mørch

Odkryłem, że to rozwiązanie zadziałało w mojej sytuacji. Dla mnie to było bardziej jak: return { a: functionA(), b: functionB(), ... }. Następnie sprawdzam względem siebie zwrócone obiekty nowych i starych wartości.
RevNoah

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

Tutaj funkcja zostanie wywołana, gdy zmieni się zarówno wiek, jak i imię.


2
Upewnij się również, że w tym przypadku nie używaj argumentów newValue i oldValue, które kąt przenosi do wywołania zwrotnego, ponieważ będą one wynikową konkatenacją, a nie tylko zmienionym polem
Akash Shinde

1

Angular wprowadzony $watchGroupw wersji 1.3, za pomocą którego możemy oglądać wiele zmiennych, z jednym $watchGroupblokiem $watchGroupprzyjmuje tablicę jako pierwszy parametr, w którym możemy uwzględnić wszystkie nasze zmienne do oglądania.

$scope.$watchGroup(['var1','var2'],function(newVals,oldVals){
   console.log("new value of var1 = " newVals[0]);
   console.log("new value of var2 = " newVals[1]);
   console.log("old value of var1 = " oldVals[0]);
   console.log("old value of var2 = " oldVals[1]);
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.