Tonton beberapa atribut $ scope


Jawaban:


585

Mulai dari AngularJS 1.3 ada metode baru yang disebut $watchGroupuntuk mengamati serangkaian ekspresi.

$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
apa bedanya dengan $ watchCollection ('[a, b]') ??
Kamil Tomšík

28
Perbedaannya adalah bahwa Anda dapat menggunakan array yang tepat alih-alih string yang terlihat seperti array
Paolo Moretti

2
Saya memiliki masalah yang sama tetapi menggunakan pola controllerAs. Dalam kasus saya, perbaikannya terdiri atas variabel dengan nama kontroler:$scope.$watchGroup(['mycustomctrl.foo', 'mycustomctrl.bar'],...
morels

1
Ini sepertinya tidak berfungsi untuk saya pada Angular 1.6. Jika saya menempatkan konsol log pada fungsi, saya dapat melihat bahwa itu hanya berjalan sekali dengan newValuesdan oldValuessebagai undefined, sementara individual menonton sifat bekerja seperti biasa.
Alejandro García Iglesias

290

Dimulai dengan AngularJS 1.1.4 Anda dapat menggunakan $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
});

Contoh plunker di sini

Dokumentasi di sini


109
Perhatikan bahwa parameter pertama bukan array. Ini adalah string yang terlihat seperti array.
MK Safi

1
Terima kasih untuk ini. jika itu bekerja untuk saya, saya akan memberi Anda seribu koin emas - yang virtual, tentu saja :)
AdityaSaxena

5
Agar jelas (butuh beberapa menit untuk saya sadari) $watchCollectiondimaksudkan untuk menyerahkan objek dan memberikan arloji untuk perubahan pada salah satu properti objek, sedangkan $watchGroupdimaksudkan untuk menyerahkan serangkaian properti individual untuk mengawasi perubahan. Sedikit berbeda untuk mengatasi masalah serupa namun berbeda. Fiuh!
Mattygabe

1
Entah bagaimana, Nilai baru dan nilai lama selalu sama ketika Anda menggunakan metode ini: plnkr.co/edit/SwwdpQcNf78pQ80hhXMr
mostruash

Terima kasih. Itu memecahkan masalah saya. Apakah ada masalah kinerja / penggunaan $ watch?
Syed Nasir Abbas

118

$watch parameter pertama juga bisa menjadi fungsi.

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

Jika dua nilai gabungan Anda sederhana, parameter pertama hanyalah ekspresi sudut secara normal. Misalnya, firstName dan lastName:

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

8
Ini seperti kasus penggunaan yang menyerukan untuk dimasukkan dalam kerangka kerja secara default. Bahkan properti yang dihitung sesederhana fullName = firstName + " " + lastNamemengharuskan lewatnya fungsi sebagai argumen pertama (daripada ekspresi sederhana seperti 'firstName, lastName'). Angular sangat kuat, tetapi ada beberapa area di mana ia bisa sangat ramah pengembang dengan cara yang tidak (tampaknya) mengganggu kinerja atau prinsip-prinsip desain.
XML

4
Well $ watch hanya mengambil ekspresi sudut, yang dievaluasi pada ruang lingkup yang dipanggil. Jadi kamu bisa melakukannya $scope.$watch('firstName + lastName', function() {...}). Anda juga bisa hanya melakukan dua jam tangan: function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged);. Saya menambahkan kasus sederhana ke jawabannya.
Andrew Joslin

Nilai tambah dalam 'firstName + lastName' adalah rangkaian string. Jadi angular hanya memeriksa apakah hasil dari rangkaian berbeda sekarang.
mb21

16
Penggabungan string membutuhkan sedikit perhatian - jika Anda mengubah "paran orman" menjadi "para norman" daripada Anda tidak akan memicu respons; terbaik untuk meletakkan pembagi seperti "\ t | \ t" antara istilah pertama dan kedua, atau hanya berpegang pada JSON yang pasti
Dave Edelhart

Meskipun amberjs menyebalkan, tetapi ia memiliki fitur ini built in! mendengar bahwa orang sudut. Saya kira melakukan jam tangan adalah cara yang paling rasional yang bisa dilakukan.
Aladdin Mhemed

70

Inilah solusi yang sangat mirip dengan kode semu asli Anda yang benar-benar berfungsi:

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

EDIT: Oke, saya pikir ini lebih baik:

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

Pada dasarnya kita melewatkan langkah json, yang tampaknya bodoh untuk memulai, tetapi tidak berhasil tanpa itu. Kuncinya adalah parameter ke-3 yang sering dihilangkan yang mengaktifkan kesetaraan objek dan bukan kesetaraan referensi. Kemudian perbandingan antara objek array yang kami buat benar-benar berfungsi dengan baik.


Saya punya pertanyaan serupa. Dan ini jawaban yang tepat untuk saya.
Calvin Cheng

Keduanya memiliki sedikit overhead kinerja jika item dalam ekspresi array bukan tipe sederhana.
null

Itu benar .. itu melakukan perbandingan kedalaman penuh dari objek komponen. Yang mungkin atau mungkin tidak apa yang Anda inginkan. Lihat jawaban yang saat ini disetujui untuk versi menggunakan sudut modern yang tidak melakukan perbandingan kedalaman penuh.
Karen Zilles

Untuk beberapa alasan, ketika saya mencoba menggunakan $ watchCollection melalui array, saya mendapatkan kesalahan TypeError: Object #<Object> has no method '$watchCollection'ini tetapi solusi ini membantu saya untuk menyelesaikan masalah saya!
abottoni

Keren, Anda bahkan dapat menonton nilai di dalam objek:$scope.$watch('[chaptercontent.Id, anchorid]', function (newValues, oldValues) { ... }, true);
Serge van den Oever

15

Anda dapat menggunakan fungsi dalam $ watchGroup untuk memilih bidang objek dalam ruang lingkup.

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

1
Mengapa Anda menggunakan _this? Bukankah ruang lingkup dimasukkan ke dalam fungsi tanpa secara eksplisit mendefinisikannya?
sg.cc

1
Saya menggunakan naskah, kode yang disajikan adalah hasil kompilasi.
Yang Zhang

12

Mengapa tidak membungkusnya dengan forEach?

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

Ini tentang overhead yang sama dengan menyediakan fungsi untuk nilai gabungan, tanpa benar-benar harus khawatir tentang komposisi nilai .


Dalam hal ini log () akan dieksekusi beberapa kali, bukan? Saya pikir dalam kasus fungsi $ nested menonton itu tidak akan. Dan seharusnya tidak dalam solusi untuk menonton beberapa atribut sekaligus.
John Doe

Tidak, log hanya dijalankan sekali per perubahan per properti yang ditonton. Mengapa itu diminta beberapa kali?
Erik Aigner

Benar, maksud saya itu tidak akan berhasil jika kita ingin menonton semuanya secara bersamaan.
John Doe

1
Tentu, mengapa tidak? Saya melakukannya dengan cara seperti itu dalam proyek saya. changed()dipanggil setiap kali ada perubahan di salah satu properti. Itu perilaku yang sama persis seolah-olah fungsi untuk nilai gabungan disediakan.
Erik Aigner

1
Ini sedikit berbeda karena jika beberapa item dalam array berubah pada saat yang sama, $ watch hanya akan memecat handler sekali alih-alih satu kali per item berubah.
bingles

11

Solusi yang sedikit lebih aman untuk menggabungkan nilai mungkin menggunakan yang berikut ini sebagai $watchfungsi Anda :

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

atau

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

5

Parameter $ watch first dapat berupa ekspresi atau fungsi sudut . Lihat dokumentasi pada $ scope. $ Watch . Ini berisi banyak info berguna tentang cara kerja metode $ watch: ketika watchExpression dipanggil, cara angular membandingkan hasil, dll.


4

bagaimana tentang:

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

2
Tanpa trueparameter ketiga to to scope.$watch(seperti pada contoh Anda), listener()akan diaktifkan setiap kali, karena hash anonim memiliki referensi yang berbeda setiap saat.
Peter V. Mørch

Saya menemukan solusi ini berfungsi untuk situasi saya. Bagi saya, itu lebih seperti: return { a: functionA(), b: functionB(), ... }. Saya kemudian memeriksa objek yang dikembalikan nilai baru dan lama terhadap satu sama lain.
RevNoah

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

Di sini fungsi akan dipanggil saat usia dan nilai nama diubah.


2
Juga pastikan dalam hal ini tidak menggunakan argumen newValue dan oldValue bahwa sudut masuk ke dalam callback karena mereka akan menjadi gabungan yang dihasilkan dan bukan hanya bidang yang diubah
Akash Shinde

1

Sudut diperkenalkan $watchGroupdalam versi 1.3 menggunakan yang kita dapat menonton beberapa variabel, dengan satu $watchGroupblok $watchGroupmengambil array sebagai parameter pertama di mana kita dapat memasukkan semua variabel kita untuk menonton.

$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]);
});
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.