Birden fazla $ kapsam özelliğini izleyin


442

Kullanarak birden fazla nesne üzerindeki olaylara abone olmanın bir yolu var mı $watch

Örneğin

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

Yanıtlar:


586

AngularJS 1.3'ten başlayarak, $watchGroupbir dizi ifadeyi gözlemlemek için çağrılan yeni bir yöntem var .

$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
$ watchCollection ('[a, b]') ile arasındaki fark nedir?
Kamil Tomšík

28
Aradaki fark, bir diziye benzeyen bir dize yerine uygun bir dizi kullanabilmenizdir
Paolo Moretti

2
Ben benzer bir sorun vardı ama controllerAs desen kullanarak. Benim durumumda düzeltme değişkenlerin başlangıcında denetleyicinin adı oluşuyordu:$scope.$watchGroup(['mycustomctrl.foo', 'mycustomctrl.bar'],...
morels

1
Bu benim için Açısal 1.6'da işe yaramıyor gibi görünüyor. Ben fonksiyonu üzerine bir konsol günlüğünü koyarsanız, ben sadece bir kez çalışır olduğunu görebilirsiniz newValuesve oldValuessıra undefinedbireysel özellikleri her zamanki gibi çalışmaya izlerken.
Alejandro García Iglesias

290

AngularJS 1.1.4 ile başlayarak şunları kullanabilirsiniz $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
});

Burada Plunker örneği

Buradaki belgeler


109
İlk parametrenin bir dizi olmadığını unutmayın . Bir diziye benzeyen bir dize.
MK Safi

1
Bunun için teşekkürler. eğer benim için işe yararsa, sana bin altın para vereceğim - elbette sanal olanlar :)
AdityaSaxena

5
Net olmak (fark etmem birkaç dakika sürdü) $watchCollectionbir nesneye teslim edilmeli ve nesnenin özelliklerinde herhangi bir değişiklik için bir saat sunarken, değişiklikleri izlemek için $watchGroupbir dizi bireysel özellik verilmelidir. Benzer ama farklı sorunları çözmek için biraz farklı. Uf!
Mattygabe

1
Her nasılsa, bu yöntemi kullandığınızda newValues ​​ve oldValues ​​her zaman eşittir: plnkr.co/edit/SwwdpQcNf78pQ80hhXMr
mostruash

Teşekkürler. Sorunumu çözdü. $ Watch kullanmanın herhangi bir performans sorunu / sorunu var mı?
Syed Nasir Abbas

118

$watch ilk parametre de bir işlev olabilir.

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

Birleştirilmiş iki değeriniz basitse, ilk parametre normalde yalnızca açısal bir ifadedir. Örneğin, firstName ve lastName:

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

8
Bu, varsayılan olarak çerçeveye dahil edilmesi için ağlayan bir kullanım örneği gibi görünüyor. Hesaplanmış bir özellik bile basit fullName = firstName + " " + lastNamebir işlevin ilk argüman olarak geçirilmesini gerektirir (örneğin, basit bir ifade yerine 'firstName, lastName'). Açısal ÇOK güçlüdür, ancak performans veya tasarım ilkelerinden ödün vermeyen (görünüşte) şekilde çok daha geliştirici dostu olabileceği bazı alanlar vardır.
XML

4
$ Watch sadece açıldığı kapsamda değerlendirilen açısal bir ifade alır. Böylece yapabilirsin $scope.$watch('firstName + lastName', function() {...}). Ayrıca, sadece iki saatler yapabilirdi: function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged);. Cevaba basit davayı ekledim.
Andrew Joslin

'FirstName + lastName' öğesindeki artı dize birleştirmesidir. Böylece açısal sadece birleştirme sonucunun şimdi farklı olup olmadığını kontrol eder.
mb21

16
Dize birleştirme biraz bakım gerektirir - eğer bir yanıt tetiklemeyeceğinizden "paran orman" ı "para norman" olarak değiştirirseniz; birinci ve ikinci dönem arasında "\ t | \ t" gibi bir bölücü koymak veya kesin olan
JSON'a

amberjs berbat olmasına rağmen, ama bu özelliği inşa var! o açısal adamları duyun. Saatleri yapmak en rasyonel yapılabilir yol sanırım.
Aladdin

70

İşte orijinal sahte kodunuza çok benzer bir çözüm, gerçekten işe yarıyor:

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

EDIT: Tamam, bence bu daha da iyi:

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

Temel olarak, başlamak için aptal gibi görünen json adımını atlıyoruz, ancak onsuz çalışmadı. Anahtar, referans eşitliğine kıyasla nesne eşitliğini açan, genellikle atlanan 3. parametredir. Sonra oluşturulan dizi nesneleri arasındaki karşılaştırmalar gerçekten doğru çalışır.


Benzer bir sorum vardı. Ve bu benim için doğru cevap.
Calvin Cheng

Dizi ifadesindeki öğeler basit türler değilse, her ikisinin de hafif bir performans yükü vardır.
boş

Bu doğru .. bileşen nesnelerin tam bir derinlemesine karşılaştırma yapıyor. Hangisi istersen olabilir veya olmayabilir. Tam bir derinlik karşılaştırması yapmayan modern açısal kullanan bir sürüm için şu anda onaylanmış cevaba bakın.
Karen Zilles

Nedense, bir dizi üzerinde $ watchCollection kullanmaya çalışırken, bu hatayı aldım TypeError: Object #<Object> has no method '$watchCollection'ama bu çözüm benim sorunumu çözmek için bana yardımcı olur!
abottoni

Harika, nesneler içindeki değerleri bile izleyebilirsiniz:$scope.$watch('[chaptercontent.Id, anchorid]', function (newValues, oldValues) { ... }, true);
Serge van den Oever

15

Kapsam içindeki bir nesnenin alanlarını seçmek için $ watchGroup içindeki işlevleri kullanabilirsiniz.

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

1
Neden kullanıyorsun _this? Kapsam açıkça tanımlanmadan işlevlere aktarılmaz mı?
sg.cc

1
Ben daktilo kullanın, sunulan kod derlenmiş sonuçtur.
Yang Zhang

12

Neden sadece a forEach?

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

Değer bileşimi hakkında endişelenmenize gerek kalmadan , birleşik değer için bir işlev sağlamakla aynı yüke sahiptir .


Bu durumda log () birkaç kez yürütülür, değil mi? Bence iç içe $ watch fonksiyonları durumunda olmaz. Ve aynı anda birkaç özelliği izlemek için çözümde olmamalıdır.
John Doe

Hayır, günlük, izlenen özellik başına değişiklik başına yalnızca bir kez yürütülür. Neden birden fazla kez çağrılsın ki?
Erik Aigner

Evet, demek istediğim, hepsini aynı anda izlemek istersek iyi olmazdı.
John Doe

1
Tabii neden olmasın? Bunu bir projemde yapıyorum. changed()özelliklerinden herhangi birinde bir değişiklik olduğunda çağrılır. Bu, birleştirilmiş değer için bir işlev sağlanmış gibi davranır.
Erik Aigner

1
Dizideki birden çok öğenin aynı anda değişmesi durumunda, $ watch öğesi, değiştirilen her öğe için bir kez yerine işleyiciyi yalnızca bir kez tetikleyecektir.
14'te

11

Değerleri birleştirmek için biraz daha güvenli bir çözüm aşağıdakileri $watchişleviniz olarak kullanmak olabilir :

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

veya

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

5

$ watch first parametresi açısal ifade veya işlev olabilir. $ Scope. $ Watch hakkındaki belgelere bakın . $ Watch yönteminin nasıl çalıştığı hakkında birçok yararlı bilgi içerir: watchExpression çağrıldığında, açısal sonuçları nasıl karşılaştırır vb.


4

nasıl:

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

2
İçin üçüncü trueparametre olmadan scope.$watch(örneğinizde olduğu gibi), listener()her seferinde tetiklenir, çünkü anonim karma her seferinde farklı bir referansa sahiptir.
Peter V.Mørch

Bu çözümün durumum için işe yaradığını gördüm. Benim için daha gibiydi: return { a: functionA(), b: functionB(), ... }. Daha sonra yeni ve eski değerlerin döndürülen nesnelerini birbirlerine karşı kontrol ederim.
Mart'ta RevNoah

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

Burada hem yaş hem de ad değeri değiştiğinde işlev çağrılır.


2
Ayrıca, bu durumda, açısal geri aramaya geçen newValue ve oldValue argümanlarını kullanmadığınızdan emin olun, çünkü bunlar sadece değişen alan değil, sonuçtaki birleştirme olacaktır
Akash Shinde

1

$watchGroupVersiyon 1.3'te tanıtılan çoklu değişkenleri izleyebileceğimiz tek bir $watchGroupblok ile $watchGroupdiziyi izlemek için tüm değişkenlerimizi dahil edebileceğimiz ilk parametre olarak alıyor.

$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]);
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.