Bagaimana cara kerja pengikatan data di AngularJS?

1957

Bagaimana cara kerja pengikatan data dalam AngularJSkerangka kerja?

Saya belum menemukan detail teknis di situs mereka . Lebih atau kurang jelas cara kerjanya saat data disebarkan dari tampilan ke model. Tetapi bagaimana AngularJS melacak perubahan properti model tanpa setter dan getter?

Saya menemukan bahwa ada pengamat JavaScript yang dapat melakukan pekerjaan ini. Tetapi mereka tidak didukung di Internet Explorer 6 dan Internet Explorer 7 . Jadi, bagaimana AngularJS tahu bahwa saya mengubah misalnya berikut ini dan mencerminkan perubahan ini pada pandangan?

myobject.myproperty="new value";
Pashec
sumber
10
Perlu diketahui bahwa sejak 1.0.0rc1 sudut Anda perlu menentukan ng-model-instan ( docs-next.angularjs.org/api/… ) agar moder Anda diperbarui secara terpisah. Kalau tidak, itu akan diperbarui pada acara blur.
Sotomajor
8
Link Marcello ini tampaknya rusak, jadi di sini adalah lagi: github.com/mhevery/angular.js/blob/master/docs/content/guide/...
jembel
6
@ orian, tautan itu buruk. diperbarui ke (saya berasumsi) adalah sama - docs.angularjs.org/guide/databinding
Kevin Meredith
11
Bagi mereka yang masih membaca pertanyaan ini, harap perhatikan bahwa Angular 2.0 telah sangat mengubah cara mereka melakukan penyatuan data sejak Angular 1.x agar dapat bekerja dengan komponen web dan mengatasi banyak masalah dalam jawaban di bawah ini.
Agustus

Jawaban:

2745

AngularJS mengingat nilai dan membandingkannya dengan nilai sebelumnya. Ini adalah pengecekan kotor dasar. Jika ada perubahan nilai, maka ini akan mengaktifkan perubahan acara.

The $apply()metode, yang adalah apa yang Anda sebut ketika Anda transisi dari dunia non-AngularJS ke dunia AngularJS, panggilan $digest(). Intisari hanyalah pengecekan kotor lama. Ini bekerja di semua browser dan benar-benar dapat diprediksi.

Membandingkan pengecekan kotor (AngularJS) vs pendengar perubahan ( KnockoutJS dan Backbone.js ): Walaupun pemeriksaan kotor mungkin tampak sederhana, dan bahkan tidak efisien (saya akan membahasnya nanti), ternyata secara semantik benar sepanjang waktu, sementara perubahan pendengar memiliki banyak kasus sudut aneh dan membutuhkan hal-hal seperti pelacakan ketergantungan untuk membuatnya lebih semantik. Pelacakan ketergantungan KnockoutJS adalah fitur cerdas untuk masalah yang tidak dimiliki AngularJS.

Masalah dengan pendengar perubahan:

  • Sintaksnya mengerikan, karena browser tidak mendukungnya secara bawaan. Ya, ada proxy, tetapi mereka tidak benar secara semantik dalam semua kasus, dan tentu saja tidak ada proxy di browser lama. Intinya adalah bahwa pemeriksaan kotor memungkinkan Anda untuk melakukan POJO , sedangkan KnockoutJS dan Backbone.js memaksa Anda untuk mewarisi dari kelas mereka, dan mengakses data Anda melalui pengakses.
  • Ubah koalesensi. Misalkan Anda memiliki berbagai item. Katakanlah Anda ingin menambahkan item ke dalam array, saat Anda mengulang untuk menambahkan, setiap kali Anda menambahkan Anda memecat acara saat perubahan, yang merender UI. Ini sangat buruk untuk kinerja. Yang Anda inginkan adalah memperbarui UI hanya sekali, pada akhirnya. Acara perubahan terlalu halus.
  • Ubah pendengar langsung ditembakkan pada setter, yang merupakan masalah, karena pendengar perubahan selanjutnya dapat mengubah data, yang memicu lebih banyak perubahan acara. Ini buruk karena di tumpukan Anda, Anda mungkin memiliki beberapa acara perubahan yang terjadi sekaligus. Misalkan Anda memiliki dua array yang perlu disinkronkan untuk alasan apa pun. Anda hanya dapat menambah satu atau yang lain, tetapi setiap kali Anda menambahkan Anda memecat suatu acara perubahan, yang sekarang memiliki pandangan dunia yang tidak konsisten. Ini adalah masalah yang sangat mirip dengan penguncian utas, yang dihindari JavaScript karena setiap panggilan balik dieksekusi secara eksklusif dan hingga selesai. Perubahan acara memecah hal ini karena setter dapat memiliki konsekuensi jangka panjang yang tidak dimaksudkan dan tidak jelas, yang menciptakan masalah utas lagi. Ternyata yang ingin Anda lakukan adalah menunda eksekusi pendengar, dan menjamin,

Bagaimana dengan kinerja?

Jadi sepertinya kita lambat, karena pemeriksaan kotor tidak efisien. Di sinilah kita perlu melihat bilangan real daripada hanya memiliki argumen teoretis, tetapi pertama-tama mari kita mendefinisikan beberapa kendala.

Manusia adalah:

  • Lambat - Apa pun yang lebih cepat dari 50 ms tidak terlihat oleh manusia dan karenanya dapat dianggap sebagai "instan".

  • Terbatas - Anda tidak dapat benar-benar menampilkan lebih dari sekitar 2.000 informasi kepada manusia pada satu halaman. Lebih dari itu UI yang benar-benar buruk, dan manusia toh tidak bisa memproses ini.

Jadi pertanyaan sebenarnya adalah ini: Berapa banyak perbandingan yang dapat Anda lakukan pada browser dalam 50 ms? Ini adalah pertanyaan yang sulit dijawab karena banyak faktor yang ikut bermain, tetapi ini adalah ujian: http://jsperf.com/angularjs-digest/6 yang menciptakan 10.000 pengamat. Pada peramban modern ini hanya membutuhkan waktu di bawah 6 ms. Di Internet Explorer 8 dibutuhkan sekitar 40 ms. Seperti yang Anda lihat, ini bukan masalah bahkan di browser lambat hari ini. Ada peringatan: perbandingan harus sederhana agar sesuai dengan batas waktu ... Sayangnya itu terlalu mudah untuk menambahkan perbandingan lambat ke AngularJS, sehingga mudah untuk membangun aplikasi lambat ketika Anda tidak tahu apa yang Anda sedang melakukan. Tetapi kami berharap memiliki jawaban dengan menyediakan modul instrumentasi, yang akan menunjukkan kepada Anda perbandingan mana yang lambat.

Ternyata video game dan GPU menggunakan pendekatan pengecekan kotor, khususnya karena konsisten. Selama mereka melewati kecepatan refresh monitor (biasanya 50-60 Hz, atau setiap 16,6-20 ms), kinerja apa pun yang merupakan pemborosan, jadi Anda lebih baik menggambar lebih banyak barang, daripada mendapatkan FPS lebih tinggi.

Misko Hevery
sumber
32
@ Mark - ya, di KO Anda hanya menambahkan .extend ({throttle: 500}) untuk menunggu 500 milidetik setelah perubahan terakhir sebelum bertindak.
Daniel Earwicker
158
Seluruh jawaban ini sangat bagus selain "Selama mereka mendapatkan 50 fps, kinerja apa pun yang sia-sia, karena mata manusia tidak bisa menghargainya, jadi Anda lebih baik menggambar lebih banyak barang, daripada mendapatkan fps lebih tinggi." Pernyataan itu sepenuhnya salah, tergantung pada aplikasi Anda. Mata pasti dapat menghargai lebih dari 50 fps, dan karena berbagai masalah dengan VR menunjukkan (baca yang terbaru dari John Carmack atau Michael Abrash, terutama GDC 2013 VR yang terakhir), 50 fps sebenarnya terlalu lambat. Selain itu, jawaban Anda sangat bagus. Saya hanya tidak ingin penyebaran informasi yang salah.
Nate Bundy
10
@ DavidvidRivers us adalah μs sama seperti di utorrent 1μs =
0.000001s
33
Pernyataan itu dapat dengan mudah dikatakan terbalik karena "Pemeriksaan kotor adalah fitur cerdas untuk masalah yang tidak dimiliki KO". ES6 menggunakan yang bisa diamati dan sudut menyingkirkan pengecekan kotor. Dunia nyata menangkap jawaban ini dan menunjukkannya salah.
Kerucut
17
"Apa pun yang lebih cepat dari 50 ms tidak terlihat oleh manusia" tidak benar. Dalam pengujian kami menemukan bahwa pelanggan kami dapat dengan mudah membedakan latensi pembaruan 50 ms (20 fps) dan latensi pembaruan 16,6 ms (60 fps). Adegan yang berjalan pada kecepatan sebelumnya secara konsisten membuat peringkat keseluruhan "bagaimana rasanya" menjadi lebih buruk, bahkan ketika orang tidak secara sadar mendaftarkan framerate.
Crashworks
323

Misko sudah memberikan deskripsi yang sangat baik tentang bagaimana data binding bekerja, tetapi saya ingin menambahkan pandangan saya tentang masalah kinerja dengan pengikatan data.

Seperti yang dikatakan Misko, sekitar 2000 binding adalah tempat Anda mulai melihat masalah, tetapi Anda seharusnya tidak memiliki lebih dari 2000 informasi di satu halaman. Ini mungkin benar, tetapi tidak semua pengikatan data terlihat oleh pengguna. Setelah Anda mulai membangun segala jenis widget atau kisi data dengan pengikatan dua arah, Anda dapat dengan mudah menekan 2.000 binding, tanpa memiliki UX yang buruk.

Pertimbangkan, misalnya, kotak kombo tempat Anda bisa mengetik teks untuk memfilter opsi yang tersedia. Kontrol semacam ini dapat memiliki ~ 150 item dan masih bisa digunakan. Jika memiliki beberapa fitur tambahan (misalnya kelas tertentu pada opsi yang dipilih saat ini) Anda mulai mendapatkan 3-5 binding per opsi. Letakkan tiga widget ini di halaman (mis. Satu untuk memilih negara, yang lain untuk memilih kota di negara tersebut, dan yang ketiga untuk memilih hotel) dan Anda sudah berada di antara 1.000 dan 2000 binding.

Atau pertimbangkan kisi-kisi data dalam aplikasi web perusahaan. 50 baris per halaman tidak masuk akal, yang masing-masing dapat memiliki 10-20 kolom. Jika Anda membangun ini dengan ng-repeat, dan / atau memiliki informasi dalam beberapa sel yang menggunakan beberapa binding, Anda bisa mendekati 2000 binding dengan grid ini saja.

Saya menemukan ini menjadi masalah besar ketika bekerja dengan AngularJS, dan satu-satunya solusi yang saya dapat temukan sejauh ini adalah membangun widget tanpa menggunakan penjilidan dua arah, alih-alih menggunakan ngOnce, pengamat deregistering dan trik serupa, atau konstruk arahan yang membangun DOM dengan manipulasi jQuery dan DOM. Saya merasa ini mengalahkan tujuan menggunakan Angular di tempat pertama.

Saya ingin mendengar saran tentang cara lain untuk menangani hal ini, tetapi mungkin saya harus menulis pertanyaan saya sendiri. Saya ingin memberi komentar, tapi ternyata terlalu lama untuk itu ...

TL; DR
Pengikatan data dapat menyebabkan masalah kinerja pada halaman yang kompleks.

MW.
sumber
26
Ya saya yang kedua. Tanggung jawab utama aplikasi kami adalah menampilkan koneksi antara entitas yang berbeda. Halaman yang diberikan mungkin memiliki 10 bagian. Setiap bagian memiliki tabel. Setiap tabel memiliki 2-5 filter typeahead. Setiap tabel memiliki 2-5 kolom, masing-masing dengan 10 baris. Sangat cepat kami mengalami masalah perf, dan pergi dengan opsi "trik serupa".
Scott Silvi
10
Apakah adil untuk mengatakan bahwa Angular tidak hanya tentang pengikatan data dan beberapa aplikasi mungkin tidak ingin menggunakan fitur ini karena alasan yang dikutip oleh orang lain? Saya pikir pendekatan DI dan modularitas itu sendiri sangat berharga; memiliki magic auto-binding itu bagus tetapi dalam setiap implementasi yang ada memiliki trade-off kinerja. Cara Angular bisa dibilang superior untuk sebagian besar aplikasi web CRUD, dan orang-orang hanya menabrak tembok dengan mencoba membawanya ke ekstrem. Akan lebih baik jika metode alternatif mendengarkan acara didukung, tetapi mungkin itu pada dasarnya terlalu kompleks untuk satu kerangka kerja?
Jason Boyd
8
Angular sekarang memiliki satu cara dan pengikatan data sekaligus untuk membantu dengan masalah ini. Selain itu sekarang memiliki indeks untuk sumber pengulang Anda, yang memungkinkan Anda mengubah daftar tanpa membangun kembali dom untuk seluruh konten.
Gaute Løken
6
@ MW. Jujur saya pikir mengikat-dulu ada di inti. Tapi sepertinya tidak. Ini hanya sesuatu yang dapat Anda lakukan saat menulis arahan Anda sendiri, pada dasarnya menghubungkan hal-hal tanpa melihatnya. Namun ada ux mod untuk itu: github.com/pasvaz/bindonce
Løken
9
Teriakan dari masa depan bagi siapa pun yang membaca ini: satu waktu mengikat sekarang menjadi fitur inti di Angular v1.3, baca lebih lanjut di sini: docs.angularjs.org/guide/expression
Nobita
158

Dengan kotor memeriksa $scopeobjek

Angular mempertahankan arraypengamat sederhana di $scopeobjek. Jika Anda memeriksa setiap $scopeAnda akan menemukan bahwa itu berisi arraydisebut $$watchers.

Setiap pengamat adalah objectyang berisi antara lain

  1. Ekspresi yang diawasi oleh pengamat. Ini mungkin hanya attributenama, atau sesuatu yang lebih rumit.
  2. Nilai ekspresi terakhir yang diketahui. Ini dapat diperiksa terhadap nilai ekspresi yang dihitung saat ini. Jika nilainya berbeda, pengamat akan memicu fungsi dan menandai $scopesebagai kotor.
  3. Suatu fungsi yang akan dieksekusi jika pengamat kotor.

Bagaimana pengamat didefinisikan

Ada banyak cara untuk mendefinisikan pengamat di AngularJS.

  • Anda secara eksplisit dapat $watchsebuah attributeon $scope.

    $scope.$watch('person.username', validateUnique);
  • Anda dapat menempatkan {{}}interpolasi di template Anda (pengamat akan dibuat untuk Anda saat ini $scope).

    <p>username: {{person.username}}</p>
  • Anda dapat meminta arahan seperti ng-modeluntuk menentukan pengamat untuk Anda.

    <input ng-model="person.username" />

The $digestsiklus memeriksa semua pengamat terhadap nilai terakhir mereka

Ketika kita berinteraksi dengan AngularJS melalui saluran normal (ng-model, ng-repeat, dll) siklus digest akan dipicu oleh arahan.

Sebuah siklus intisari adalah traversal pertama-utama dari $scopedan semua anak-anaknya . Untuk masing-masing $scope object, kami mengulanginya $$watchers arraydan mengevaluasi semua ekspresi. Jika nilai ekspresi baru berbeda dari nilai terakhir yang diketahui, fungsi pengamat disebut. Fungsi ini dapat mengkompilasi ulang bagian DOM, mengkompilasi ulang nilai pada $scope, memicu AJAX request, apa pun yang Anda perlu lakukan.

Setiap ruang lingkup dilalui dan setiap ekspresi arloji dievaluasi dan diperiksa terhadap nilai terakhir.

Jika seorang pengamat dipicu, $scopeitu kotor

Jika pengamat dipicu, aplikasi tahu ada sesuatu yang berubah, dan $scopeditandai sebagai kotor.

Fungsi pengamat dapat mengubah atribut lainnya pada $scopeatau pada induknya $scope. Jika satu $watcherfungsi telah dipicu, kami tidak dapat menjamin bahwa fungsi kami yang lain $scopemasih bersih, jadi kami menjalankan seluruh siklus intisari lagi.

Ini karena AngularJS memiliki ikatan dua arah, sehingga data dapat dilewatkan kembali ke $scopepohon. Kami dapat mengubah nilai pada yang lebih tinggi $scopeyang telah dicerna. Mungkin kami mengubah nilai pada $rootScope.

Jika $digestkotor, kami menjalankan seluruh $digestsiklus lagi

Kami terus-menerus mengulangi $digestsiklus hingga siklus digest muncul bersih (semua $watchekspresi memiliki nilai yang sama seperti pada siklus sebelumnya), atau kami mencapai batas digest. Secara default, batas ini ditetapkan 10.

Jika kami mencapai batas cerna, AngularJS akan memunculkan kesalahan di konsol:

10 $digest() iterations reached. Aborting!

Intisnya keras pada mesin tetapi mudah pada pengembang

Seperti yang Anda lihat, setiap kali ada perubahan dalam aplikasi AngularJS, AngularJS akan memeriksa setiap pengamat tunggal dalam $scopehierarki untuk melihat bagaimana merespons. Untuk pengembang, ini adalah anugerah produktivitas besar, karena Anda sekarang perlu menulis hampir tidak ada kode pengkabelan, AngularJS hanya akan melihat jika suatu nilai telah berubah, dan membuat aplikasi lainnya konsisten dengan perubahan tersebut.

Dari perspektif mesin, ini sangat tidak efisien dan akan memperlambat aplikasi kita jika kita membuat terlalu banyak pengamat. Misko telah mengutip angka sekitar 4000 pengamat sebelum aplikasi Anda terasa lambat di peramban yang lebih lama.

Batas ini mudah dijangkau jika Anda ng-repeatmelebihi besar JSON arraymisalnya. Anda dapat mengurangi ini dengan menggunakan fitur-fitur seperti ikatan satu kali untuk mengkompilasi template tanpa membuat pengamat.

Cara menghindari membuat terlalu banyak pengamat

Setiap kali pengguna Anda berinteraksi dengan aplikasi Anda, setiap pengamat tunggal di aplikasi Anda akan dievaluasi setidaknya satu kali. Sebagian besar mengoptimalkan aplikasi AngularJS adalah mengurangi jumlah pengamat di $scopepohon Anda . Salah satu cara mudah untuk melakukan ini adalah dengan mengikat satu kali .

Jika Anda memiliki data yang jarang berubah, Anda hanya dapat mengikatnya sekali menggunakan :: sintaks, seperti:

<p>{{::person.username}}</p>

atau

<p ng-bind="::person.username"></p>

Ikatan hanya akan dipicu ketika template yang berisi diberikan dan data dimasukkan $scope.

Ini sangat penting ketika Anda memiliki ng-repeatbanyak item.

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>
superluminary
sumber
Terima kasih @ user2864740 - meskipun benar bahwa jawaban Misko harus atas. Dia tahu kerangka kerja lebih baik daripada siapa pun, dan itu cukup keren bahwa dia terlibat dengan Stack Overflow ..
superluminary
4
Saya tidak setuju bahwa kata jawaban harus di atas; ada perbedaan antara mengetahui sesuatu dan menulis jawaban yang relevan / terperinci untuk pertanyaan tertentu. Ada cara yang lebih baik untuk mendapatkan pujian. Pokoknya ..
user2864740
1
Saya tidak meragukan hal itu benar, tetapi pertanyaan pertanyaan dan jawaban jawaban :)
user2864740
3
Jawaban yang bagus meliputi bagaimana pemeriksaan kotor itu dan apa yang sebenarnya dievaluasi, satu hal yang tidak terlalu jelas dalam jawaban Misko.
strider
3
Jawaban luar biasa dan terperinci. @superluminary, terima kasih atas jawaban seperti itu. Selain itu, setelah membaca jawaban ini, saya sampai pada titik bahwa kita tidak boleh menambahkan ekspresi non-idempoten sebagai ekspresi yang diawasi.
Mangu Singh Rajpurohit
81

Ini adalah pemahaman dasar saya. Mungkin salah!

  1. Item ditonton dengan melewati fungsi (mengembalikan barang yang akan ditonton) ke $watchmetode.
  2. Perubahan pada item yang ditonton harus dilakukan dalam blok kode yang dibungkus oleh $applymetode ini.
  3. Pada akhir $applyyang $digestmetode dipanggil yang berjalan melalui masing-masing jam tangan dan memeriksa untuk melihat apakah mereka berubah sejak terakhir kali $digestberlari.
  4. Jika ada perubahan yang ditemukan maka intisari dipanggil lagi sampai semua perubahan stabil.

Dalam perkembangan normal, sintaks pengikatan data dalam HTML memberi tahu kompiler AngularJS untuk membuat jam tangan untuk Anda dan metode pengontrol sudah dijalankan di dalam $apply. Jadi untuk pengembang aplikasi semuanya transparan.

Pete BD
sumber
4
Kapan metode yang diterapkan dipicu?
numan salati
3
@ EliseuMonar Loop digest berjalan sebagai hasil dari beberapa peristiwa atau memanggil $ apply (), itu tidak dipanggil secara periodik berdasarkan timer. lihat Bagaimana fungsi $ watch AngularJS bekerja? dan bagaimana cara kerja binding dan digesting di AngularJS?
adl
1
@remi, saya tidak khawatir tentang versi terakhir AngularJS. Apakah mereka sudah menggunakan proxy atau Object.observe? Jika tidak, mereka masih dalam era pemeriksaan kotor, yang membangun loop waktu untuk melihat apakah atribut model telah berubah.
Eliseu Monar dos Santos
1
saya pernah membaca bahwa digest akan berjalan maksimal sepuluh kali sitepoint.com/understanding-angulars-apply-digest
user137717
62

Saya bertanya-tanya sendiri untuk sementara waktu. Tanpa setters bagaimana AngularJSpemberitahuan berubah pada $scopeobjek? Apakah itu polling mereka?

Apa yang sebenarnya dilakukannya adalah ini: Setiap tempat "normal" yang Anda modifikasi model sudah dipanggil dari nyali AngularJS, sehingga secara otomatis memanggil $applyAnda setelah kode Anda berjalan. Katakanlah controller Anda memiliki metode yang terhubung ng-clickpada beberapa elemen. Karena AngularJSkabel memanggil metode itu bersama untuk Anda, ia memiliki kesempatan untuk melakukan $applydi tempat yang tepat. Demikian juga, untuk ekspresi yang muncul tepat di tampilan, mereka dieksekusi oleh AngularJSbegitu itu $apply.

Ketika dokumentasi berbicara tentang keharusan memanggil $applysecara manual untuk kode di luarAngularJS , itu berbicara tentang kode yang, ketika dijalankan, tidak berasal dari AngularJSdirinya sendiri dalam tumpukan panggilan.

jpsimons
sumber
32

Menjelaskan dengan Gambar:

Pengikatan data membutuhkan pemetaan

Referensi dalam ruang lingkup bukanlah referensi dalam template. Saat Anda mengikat data dua objek, Anda membutuhkan objek ketiga yang mendengarkan objek pertama dan memodifikasi objek lainnya.

masukkan deskripsi gambar di sini

Di sini, ketika Anda memodifikasi <input>, Anda menyentuh data-ref3 . Dan mekanisme klasik data-bind akan mengubah data-ref4 . Jadi bagaimana {{data}}ekspresi lainnya akan bergerak?

Acara mengarah ke $ digest ()

masukkan deskripsi gambar di sini

Angular mempertahankan oldValuedan newValuesetiap ikatan. Dan setelah setiap acara Angular , $digest()loop terkenal akan memeriksa WatchList untuk melihat apakah ada yang berubah. Ini acara Sudut adalah ng-click, ng-change, $httpselesai ... The $digest()akan loop selama setiap oldValueberbeda dari newValue.

Pada gambar sebelumnya, ia akan melihat bahwa data-ref1 dan data-ref2 telah berubah.

Kesimpulan

Ini sedikit seperti Telur dan Ayam. Anda tidak pernah tahu siapa yang memulai, tetapi mudah-mudahan ini berfungsi sebagian besar waktu seperti yang diharapkan.

Poin lainnya adalah Anda dapat dengan mudah memahami dampak mendalam dari pengikatan sederhana pada memori dan CPU. Semoga Desktop cukup gemuk untuk menangani ini. Ponsel tidak sekuat itu.

Nicolas Zozol
sumber
22

Jelas tidak ada pemeriksaan berkala Scopeapakah ada perubahan pada Objek yang dilampirkan padanya. Tidak semua objek yang dilampirkan pada ruang lingkup ditonton. Cakupan menjaga prototipe $$ pengamat . Scopehanya beralih melalui ini $$watchersketika $digestdipanggil.

Angular menambahkan pengamat ke $$ pengamat untuk masing-masing

  1. {{expression}} - Di templat Anda (dan di mana pun di mana ada ekspresi) atau ketika kami mendefinisikan ng-model.
  2. $ scope. $ watch ('expression / function') - Dalam JavaScript Anda, kami hanya dapat melampirkan objek scope untuk ditonton oleh angular.

$ watch function mengambil tiga parameter:

  1. Pertama adalah fungsi pengamat yang hanya mengembalikan objek atau kita bisa menambahkan ekspresi.

  2. Yang kedua adalah fungsi pendengar yang akan dipanggil ketika ada perubahan pada objek. Semua hal seperti perubahan DOM akan diimplementasikan dalam fungsi ini.

  3. Yang ketiga adalah parameter opsional yang menggunakan boolean. Jika benar, sudut dalam memperhatikan objek & jika sudut salahnya hanya melakukan referensi menonton pada objek. Penerapan $ watch secara kasar terlihat seperti ini

Scope.prototype.$watch = function(watchFn, listenerFn) {
   var watcher = {
       watchFn: watchFn,
       listenerFn: listenerFn || function() { },
       last: initWatchVal  // initWatchVal is typically undefined
   };
   this.$$watchers.push(watcher); // pushing the Watcher Object to Watchers  
};

Ada hal yang menarik dalam Angular yang disebut Digest Cycle. Siklus $ digest dimulai sebagai hasil dari panggilan ke $ scope. $ Digest (). Asumsikan bahwa Anda mengubah model $ scope dalam fungsi handler melalui arahan ng-klik. Jika demikian, AngularJS secara otomatis memicu siklus $ digest dengan memanggil $ digest (). Selain ng-klik, ada beberapa arahan / layanan built-in lain yang memungkinkan Anda mengubah model (mis. Ng-model, $ timeout, dll) dan secara otomatis memicu siklus $ digest. Implementasi kasar dari $ digest terlihat seperti ini.

Scope.prototype.$digest = function() {
      var dirty;
      do {
          dirty = this.$$digestOnce();
      } while (dirty);
}
Scope.prototype.$$digestOnce = function() {
   var self = this;
   var newValue, oldValue, dirty;
   _.forEach(this.$$watchers, function(watcher) {
          newValue = watcher.watchFn(self);
          oldValue = watcher.last;   // It just remembers the last value for dirty checking
          if (newValue !== oldValue) { //Dirty checking of References 
   // For Deep checking the object , code of Value     
   // based checking of Object should be implemented here
             watcher.last = newValue;
             watcher.listenerFn(newValue,
                  (oldValue === initWatchVal ? newValue : oldValue),
                   self);
          dirty = true;
          }
     });
   return dirty;
 };

Jika kami menggunakan fungsi setTimeout () JavaScript untuk memperbarui model ruang lingkup, Angular tidak memiliki cara untuk mengetahui apa yang mungkin Anda ubah. Dalam hal ini adalah tanggung jawab kami untuk memanggil $ apply () secara manual, yang memicu siklus $ digest. Demikian pula, jika Anda memiliki arahan yang mengatur pendengar acara DOM dan mengubah beberapa model di dalam fungsi handler, Anda perlu memanggil $ apply () untuk memastikan perubahan itu berlaku. Gagasan besar dari $ apply adalah bahwa kita dapat mengeksekusi beberapa kode yang tidak menyadari Angular, kode itu mungkin masih mengubah hal-hal pada ruang lingkup. Jika kita membungkus kode itu dalam $ apply, itu akan menangani panggilan $ digest (). Implementasi kasar dari $ apply ().

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};
Sasank Sunkavalli
sumber
15

AngularJS menangani mekanisme pengikatan data dengan bantuan tiga fungsi hebat: $ watch () , $ digest () dan $ apply () . Sebagian besar waktu AngularJS akan memanggil $ scope. $ Watch () dan $ scope. $ Digest (), tetapi dalam beberapa kasus Anda mungkin harus memanggil fungsi-fungsi ini secara manual untuk memperbarui dengan nilai-nilai baru.

$ tonton () : -

Fungsi ini digunakan untuk mengamati perubahan dalam variabel pada $ scope. Ini menerima tiga parameter: ekspresi, objek pendengar dan kesetaraan, di mana objek pendengar dan kesetaraan adalah parameter opsional.

$ digest () -

Fungsi ini berulang melalui semua jam tangan di objek $ scope, dan $ child object-nya
(jika ada). Ketika $ digest () berulang di atas jam tangan, ia memeriksa apakah nilai ekspresi telah berubah. Jika nilainya berubah, AngularJS memanggil pendengar dengan nilai baru dan lama. Fungsi $ digest () dipanggil kapan pun AngularJS menganggapnya perlu. Misalnya, setelah klik tombol, atau setelah panggilan AJAX. Anda mungkin memiliki beberapa kasus di mana AngularJS tidak memanggil fungsi $ digest () untuk Anda. Dalam hal ini Anda harus menyebutnya sendiri.

$ apply () -

Angular melakukan pembaruan secara ajaib hanya perubahan model yang ada di dalam konteks AngularJS. Saat Anda mengubah model apa pun di luar konteks Angular (seperti acara DOM browser, setTimeout, XHR, atau pustaka pihak ketiga), maka Anda perlu memberi tahu Angular tentang perubahan tersebut dengan menelepon $ apply () secara manual. Ketika panggilan fungsi $ apply () selesai, panggilan AngularJS $ digest () secara internal, sehingga semua ikatan data diperbarui.

Bharath Kumar
sumber
7

Kebetulan saya perlu menautkan model data seseorang dengan formulir, yang saya lakukan adalah pemetaan langsung data dengan formulir.

Misalnya jika modelnya memiliki sesuatu seperti:

$scope.model.people.name

Input kontrol dari formulir:

<input type="text" name="namePeople" model="model.people.name">

Dengan begitu jika Anda memodifikasi nilai pengontrol objek, ini akan tercermin secara otomatis dalam tampilan.

Contoh di mana saya lulus model diperbarui dari data server adalah ketika Anda meminta kode pos dan kode pos berdasarkan pada beban tertulis daftar koloni dan kota yang terkait dengan tampilan itu, dan secara default menetapkan nilai pertama dengan pengguna. Dan ini saya bekerja dengan sangat baik, apa yang terjadi, adalah bahwa angularJSkadang - kadang membutuhkan beberapa detik untuk menyegarkan model, untuk melakukan ini Anda dapat meletakkan pemintal saat menampilkan data.

gartox
sumber
14
Saya membaca jawaban ini 5 kali dan saya masih tidak mengerti apa yang dimaksud di sini.
sbedulin
1
Jawabannya seperti teka-teki bagi saya
Aman
6
  1. Pengikatan data satu arah adalah suatu pendekatan di mana nilai diambil dari model data dan dimasukkan ke dalam elemen HTML. Tidak ada cara untuk memperbarui model dari tampilan. Ini digunakan dalam sistem template klasik. Sistem ini mengikat data hanya dalam satu arah.

  2. Pengikatan data di aplikasi Angular adalah sinkronisasi data secara otomatis antara model dan komponen tampilan.

Pengikatan data memungkinkan Anda memperlakukan model sebagai satu-satunya sumber kebenaran dalam aplikasi Anda. Tampilan adalah proyeksi model setiap saat. Jika model diubah, tampilan mencerminkan perubahan dan sebaliknya.

Shankar Gangadhar
sumber
5

Berikut adalah contoh pengikatan data dengan AngularJS, menggunakan bidang input. Saya akan jelaskan nanti

Kode HTML

<div ng-app="myApp" ng-controller="myCtrl" class="formInput">
     <input type="text" ng-model="watchInput" Placeholder="type something"/>
     <p>{{watchInput}}</p> 
</div>

Kode AngularJS

myApp = angular.module ("myApp", []);
myApp.controller("myCtrl", ["$scope", function($scope){
  //Your Controller code goes here
}]);

Seperti yang Anda lihat dalam contoh di atas, AngularJS menggunakan ng-modeluntuk mendengarkan dan menonton apa yang terjadi pada elemen HTML, terutama di inputbidang. Ketika sesuatu terjadi, lakukan sesuatu. Dalam kasus kami, ng-modelterikat dengan pandangan kami, menggunakan notasi kumis {{}}. Apa pun yang diketik di dalam bidang input ditampilkan di layar secara instan. Dan itulah keindahan dari pengikatan data, menggunakan AngularJS dalam bentuknya yang paling sederhana.

Semoga ini membantu.

Lihat contoh yang berfungsi di sini di Codepen

AllJs
sumber
5

AngularJs mendukung pengikatan data dua arah .
Berarti Anda dapat mengakses data View -> Controller & Controller -> View

Untuk Kel.

1)

// If $scope have some value in Controller. 
$scope.name = "Peter";

// HTML
<div> {{ name }} </div>

O / P

Peter

Anda dapat mengikat data dalam ng-modelSuka: -
2)

<input ng-model="name" />

<div> {{ name }} </div>

Di sini, dalam contoh di atas, apa pun yang akan diberikan oleh pengguna, Itu akan terlihat dalam <div>tag.

Jika ingin mengikat input dari html ke controller: -
3)

<form name="myForm" ng-submit="registration()">
   <label> Name </lbel>
   <input ng-model="name" />
</form>

Di sini jika Anda ingin menggunakan input namepada controller,

$scope.name = {};

$scope.registration = function() {
   console.log("You will get the name here ", $scope.name);
};

ng-modelmengikat pandangan kita dan membuatnya dalam ekspresi {{ }}.
ng-modeladalah data yang ditampilkan kepada pengguna dalam tampilan dan yang berinteraksi dengan pengguna.
Sehingga mudah untuk mengikat data di AngularJs.

ojus kulkarni
sumber
4

Angular.js membuat pengamat untuk setiap model yang kami buat dalam tampilan. Setiap kali model diubah, kelas "ng-dirty" ditambahkan ke model, sehingga pengamat akan mengamati semua model yang memiliki kelas "ng-dirty" & memperbarui nilainya dalam controller & sebaliknya.

Shankar Gangadhar
sumber
3

pengikatan data:

Apa yang mengikat data?

Setiap kali pengguna mengubah data dalam tampilan, terjadi pembaruan dari perubahan dalam model lingkup, dan sebaliknya.

Bagaimana itu mungkin?

Jawaban singkat: Dengan bantuan siklus cerna.

Deskripsi: Angular js mengatur pengamat pada model ruang lingkup, yang mengaktifkan fungsi pendengar jika ada perubahan dalam model.

$scope.$watch('modelVar' , function(newValue,oldValue){

// Kode pembaruan Dom dengan nilai baru

});

Jadi Kapan dan Bagaimana fungsi pengamat dipanggil?

Fungsi pengamat disebut sebagai bagian dari siklus digest.

Siklus pencernaan disebut dipicu secara otomatis sebagai bagian dari sudut js yang dibangun dalam arahan / layanan seperti ng-model, ng-bind, $ timeout, ng-klik dan lain-lain .. yang memungkinkan Anda memicu siklus intisari.

Fungsi siklus pencernaan:

$scope.$digest() -> digest cycle against the current scope.
$scope.$apply() -> digest cycle against the parent scope 

yaitu$rootScope.$apply()

Catatan: $ apply () sama dengan $ rootScope. $ Digest () ini berarti pemeriksaan kotor dimulai langsung dari root atau atas atau ruang lingkup orang tua ke semua cakupan $ child dalam aplikasi js angular.

Fitur di atas berfungsi di browser IE untuk versi yang disebutkan juga hanya dengan memastikan aplikasi Anda adalah aplikasi js angular yang berarti Anda menggunakan file skrip kerangka kerja angular yang dirujuk dalam tag skrip.

Terima kasih.

Dhana
sumber