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.