Apa yang setara dengan Angular dengan arloji AngularJS $?

213

Di AngularJS Anda dapat menentukan pengamat untuk mengamati perubahan dalam variabel lingkup menggunakan $watchfungsi $scope. Apa yang setara dengan mengawasi perubahan variabel (misalnya, variabel komponen) di Angular?

Erwin
sumber
Gunakan get accessor dalam naskah.
jmvtrinidad
periksa artikel ini yang menjelaskan perbedaannya
Max Koretskyi

Jawaban:

268

Di Angular 2, deteksi perubahan otomatis ... $scope.$watch()dan $scope.$digest()RIP

Sayangnya, bagian Deteksi Perubahan panduan pengembang belum ditulis (ada pengganti di dekat bagian bawah halaman Tinjauan Arsitektur , di bagian "The Other Stuff").

Inilah pemahaman saya tentang cara kerja deteksi perubahan:

  • Zone.js "monyet menambal dunia" - ini mencegat semua API asinkron di peramban (saat Angular berjalan). Inilah sebabnya mengapa kita dapat menggunakan setTimeout()di dalam komponen kita daripada sesuatu seperti $timeout... karena setTimeout()monyet ditambal.
  • Angular membangun dan memelihara pohon "detektor perubahan". Ada satu detektor perubahan (kelas) per komponen / arahan. (Anda bisa mendapatkan akses ke objek ini dengan menyuntikkan ChangeDetectorRef.) Detektor perubahan ini dibuat saat Angular membuat komponen. Mereka melacak keadaan semua ikatan Anda, untuk pemeriksaan kotor. Ini, dalam arti tertentu, mirip dengan otomatis $watches()yang akan diatur oleh Angular 1 untuk {{}}binding template.
    Tidak seperti Angular 1, grafik deteksi perubahan adalah pohon terarah dan tidak dapat memiliki siklus (ini membuat Angular 2 jauh lebih performan, seperti yang akan kita lihat di bawah).
  • Ketika suatu peristiwa menyala (di dalam zona Angular), kode yang kami tulis (panggilan balik event handler) berjalan. Ia dapat memperbarui data apa pun yang diinginkannya - model / status aplikasi bersama dan / atau status tampilan komponen.
  • Setelah itu, karena kait Zone.js ditambahkan, ia kemudian menjalankan algoritma deteksi perubahan Angular. Secara default (yaitu, jika Anda tidak menggunakanonPush strategi deteksi perubahan pada salah satu komponen Anda), setiap komponen di pohon diperiksa sekali (TTL = 1) ... dari atas, dalam urutan kedalaman-pertama. (Ya, jika Anda dalam mode dev, deteksi perubahan berjalan dua kali (TTL = 2). Lihat ApplicationRef.tick () untuk informasi lebih lanjut tentang ini.) Ini melakukan pemeriksaan kotor pada semua binding Anda, menggunakan perubahan objek detektor.
    • Kait siklus hidup disebut sebagai bagian dari deteksi perubahan.
      Jika data komponen yang ingin Anda tonton adalah properti input primitif (String, boolean, number), Anda dapat menerapkan ngOnChanges()pemberitahuan perubahan.
      Jika properti input adalah tipe referensi (objek, array, dll.), Tetapi referensi tidak berubah (misalnya, Anda menambahkan item ke array yang ada), Anda harus menerapkan ngDoCheck()(lihat jawaban SO ini untuk lebih lanjut hal ini).
      Anda hanya boleh mengubah properti komponen dan / atau properti komponen turunan (karena implementasi walk tree tunggal - yaitu, aliran data searah). Di sini ada plunker yang melanggar itu. Pipa stateful juga dapat membuat Anda tersandung di sini.
  • Untuk perubahan mengikat apa pun yang ditemukan, Komponen diperbarui, dan kemudian DOM diperbarui. Ubah deteksi sekarang selesai.
  • Browser memperhatikan DOM mengubah dan memperbarui layar.

Referensi lain untuk mempelajari lebih lanjut:

Mark Rajcok
sumber
window.addEventListener () tidak memicu deteksi ketika variabel diubah ... itu membuatku gila, tidak ada apa-apa di sana.
Albert James Teddy
@AlbertJamesTeddy, lihat host, dokumentasi "Host Listeners" di DirectiveMetadata API doc . Ini menjelaskan cara mendengarkan acara global dari dalam zona Angular (jadi deteksi perubahan akan dipicu seperti yang diinginkan). Jawaban ini memiliki plunker yang berfungsi.
Mark Rajcok
tautan ini akan sangat membantu ..
refactor
@ MarkRajcok, saya mengambil kebebasan untuk menambahkan referensi ke artikel saya tentang deteksi perubahan. Semoga kamu tidak keberatan. Ini menjelaskan dengan sangat terperinci apa yang terjadi di bawah tenda.
Max Koretskyi
Mengenai plunkr yang melanggar aturan aliran data searah, saya ingin menambahkan bahwa jika Anda menjalankan plunkr dengan enableProdMode (), Anda tidak akan melihat pembaruan apa pun dalam tampilan induk, karena detektor perubahan hanya berjalan sekali.
Mister_L
93

Perilaku ini sekarang merupakan bagian dari siklus hidup komponen.

Sebuah komponen dapat mengimplementasikan metode ngOnChanges di antarmuka OnChanges untuk mendapatkan akses ke perubahan input.

Contoh:

import {Component, Input, OnChanges} from 'angular2/core';


@Component({
  selector: 'hero-comp',
  templateUrl: 'app/components/hero-comp/hero-comp.html',
  styleUrls: ['app/components/hero-comp/hero-comp.css'],
  providers: [],
  directives: [],

  pipes: [],
  inputs:['hero', 'real']
})
export class HeroComp implements OnChanges{
  @Input() hero:Hero;
  @Input() real:string;
  constructor() {
  }
  ngOnChanges(changes) {
      console.log(changes);
  }
}
toskv
sumber
77
ini hanya berlaku untuk @Input (). jika Anda ingin melacak perubahan data komponen Anda sendiri, ini tidak akan berfungsi
LanderV
4
Saya tidak bisa mendapatkan perubahan variabel sederhana (misalnya boolean). Hanya perubahan objek yang terdeteksi.
mtoloo
mengapa perlu menambahkan "input" array di dekorator komponen? deteksi perubahan akan bekerja tanpa ini juga.
Gil Epshtain
68

Jika, selain pengikatan dua arah otomatis, Anda ingin memanggil fungsi saat suatu nilai berubah, Anda bisa memecah sintaks pintasan pengikatan dua arah ke versi yang lebih verbose.

<input [(ngModel)]="yourVar"></input>

adalah singkatan

<input [ngModel]="yourVar" (ngModelChange)="yourVar=$event"></input>

(lihat misalnya http://victorsavkin.com/post/119943127151/angular-2-template-syntax )

Anda dapat melakukan sesuatu seperti ini:

<input [(ngModel)]="yourVar" (ngModelChange)="changedExtraHandler($event)"></input>

supermikko
sumber
Pada contoh terakhir Anda bermaksud menghapus [] di sekitar ngModel?
Eugene Kulabuhov
16

Anda dapat menggunakan getter functionatau get accessoruntuk bertindak sebagai menonton di sudut 2.

Lihat demo di sini .

import {Component} from 'angular2/core';

@Component({
  // Declare the tag name in index.html to where the component attaches
  selector: 'hello-world',

  // Location of the template for this component
  template: `
  <button (click)="OnPushArray1()">Push 1</button>
  <div>
    I'm array 1 {{ array1 | json }}
  </div>
  <button (click)="OnPushArray2()">Push 2</button>
  <div>
    I'm array 2 {{ array2 | json }}
  </div>
  I'm concatenated {{ concatenatedArray | json }}
  <div>
    I'm length of two arrays {{ arrayLength | json }}
  </div>`
})
export class HelloWorld {
    array1: any[] = [];
    array2: any[] = [];

    get concatenatedArray(): any[] {
      return this.array1.concat(this.array2);
    }

    get arrayLength(): number {
      return this.concatenatedArray.length;
    }

    OnPushArray1() {
        this.array1.push(this.array1.length);
    }

    OnPushArray2() {
        this.array2.push(this.array2.length);
    }
}
jmvtrinidad
sumber
12

Berikut adalah pendekatan lain menggunakan fungsi pengambil dan penyetel untuk model.

@Component({
  selector: 'input-language',
  template: `
  …
  <input 
    type="text" 
    placeholder="Language" 
    [(ngModel)]="query" 
  />
  `,
})
export class InputLanguageComponent {

  set query(value) {
    this._query = value;
    console.log('query set to :', value)
  }

  get query() {
    return this._query;
  }
}
Pilih
sumber
4
Subjek ini gila. Saya memiliki objek dengan banyak properti terkait dengan bentuk yang kompleks. Saya tidak ingin menambahkan (change)handler (s) pada masing-masing dari mereka; Saya tidak ingin menambahkan get|setss ke setiap properti dalam model saya; tidak akan membantu menambahkan get|setuntuk this.object; ngOnChanges() hanya mendeteksi perubahan @Inputs . Manna suci! Apa yang mereka lakukan pada kita ??? Beri kami semacam pengawasan mendalam!
Cody
6

Jika Anda ingin menjadikannya 2 cara mengikat, Anda dapat menggunakannya [(yourVar)] , tetapi Anda harus menerapkannyayourVarChange acara dan menyebutnya setiap kali perubahan variabel Anda.

Sesuatu seperti ini untuk melacak perubahan pahlawan

@Output() heroChange = new EventEmitter();

dan kemudian saat pahlawanmu diganti, teleponlah this.heroChange.emit(this.hero);

itu [(hero)] mengikat akan melakukan sisanya untuk Anda

lihat contoh di sini:

http://plnkr.co/edit/efOGIJ0POh1XQeRZctSx?p=preview

Mohy Eldeen
sumber
2

Ini tidak menjawab pertanyaan secara langsung, tetapi pada kesempatan yang berbeda saya mendarat di pertanyaan Stack Overflow ini untuk menyelesaikan sesuatu yang saya akan gunakan $ watch for in angularJs. Saya akhirnya menggunakan pendekatan lain dari yang dijelaskan dalam jawaban saat ini, dan ingin membaginya jika ada yang merasa berguna.

Teknik yang saya gunakan untuk mencapai sesuatu yang serupa $watchadalah dengan menggunakan BehaviorSubject( lebih banyak tentang topik di sini ) dalam layanan Angular, dan membiarkan komponen saya berlangganan untuk mendapatkan (melihat) perubahan. Ini mirip dengan $watchdi angularJs, tetapi membutuhkan lebih banyak pengaturan dan pemahaman.

Dalam komponen saya:

export class HelloComponent {
  name: string;
  // inject our service, which holds the object we want to watch.
  constructor(private helloService: HelloService){
    // Here I am "watching" for changes by subscribing
    this.helloService.getGreeting().subscribe( greeting => {
      this.name = greeting.value;
    });
  }
}

Dalam pelayanan saya

export class HelloService {
  private helloSubject = new BehaviorSubject<{value: string}>({value: 'hello'});
  constructor(){}
  // similar to using $watch, in order to get updates of our object 
  getGreeting(): Observable<{value:string}> {
    return this.helloSubject;
  }
  // Each time this method is called, each subscriber will receive the updated greeting.
  setGreeting(greeting: string) {
    this.helloSubject.next({value: greeting});
  }
}

Ini demo di Stackblitz

John
sumber