Diperbarui untuk RC.5
Dengan Angular 2 kita dapat melakukan debounce menggunakan operator RxJS debounceTime()
pada kontrol form yang valueChanges
dapat diamati:
import {Component} from '@angular/core';
import {FormControl} from '@angular/forms';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/throttleTime';
import 'rxjs/add/observable/fromEvent';
@Component({
selector: 'my-app',
template: `<input type=text [value]="firstName" [formControl]="firstNameControl">
<br>{{firstName}}`
})
export class AppComponent {
firstName = 'Name';
firstNameControl = new FormControl();
formCtrlSub: Subscription;
resizeSub: Subscription;
ngOnInit() {
// debounce keystroke events
this.formCtrlSub = this.firstNameControl.valueChanges
.debounceTime(1000)
.subscribe(newValue => this.firstName = newValue);
// throttle resize events
this.resizeSub = Observable.fromEvent(window, 'resize')
.throttleTime(200)
.subscribe(e => {
console.log('resize event', e);
this.firstName += '*'; // change something to show it worked
});
}
ngDoCheck() { console.log('change detection'); }
ngOnDestroy() {
this.formCtrlSub.unsubscribe();
this.resizeSub .unsubscribe();
}
}
Plunker
Kode di atas juga termasuk contoh bagaimana cara throttle window mengubah ukuran acara, seperti yang diminta oleh @albanx dalam komentar di bawah ini.
Meskipun kode di atas mungkin merupakan cara Angular untuk melakukannya, itu tidak efisien. Setiap keystroke dan setiap peristiwa pengubahan ukuran, meskipun mereka ditolak dan dicekik, menghasilkan perubahan pendeteksian berjalan. Dengan kata lain, debouncing dan pelambatan tidak mempengaruhi seberapa sering perubahan pendeteksian berjalan . (Saya menemukan komentar GitHub oleh Tobias Bosch yang mengkonfirmasi ini.) Anda dapat melihat ini ketika Anda menjalankan plunker dan Anda melihat berapa kali ngDoCheck()
dipanggil ketika Anda mengetik ke dalam kotak input atau mengubah ukuran jendela. (Gunakan tombol "x" biru untuk menjalankan plunker di jendela terpisah untuk melihat ukurannya.)
Teknik yang lebih efisien adalah membuat RxJS Dapat Diamati sendiri dari acara, di luar "zona" Angular. Dengan cara ini, deteksi perubahan tidak dipanggil setiap kali suatu peristiwa menyala. Kemudian, dalam metode panggilan balik berlangganan Anda, secara manual memicu deteksi perubahan - yaitu, Anda mengontrol kapan deteksi perubahan dipanggil:
import {Component, NgZone, ChangeDetectorRef, ApplicationRef,
ViewChild, ElementRef} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/throttleTime';
import 'rxjs/add/observable/fromEvent';
@Component({
selector: 'my-app',
template: `<input #input type=text [value]="firstName">
<br>{{firstName}}`
})
export class AppComponent {
firstName = 'Name';
keyupSub: Subscription;
resizeSub: Subscription;
@ViewChild('input') inputElRef: ElementRef;
constructor(private ngzone: NgZone, private cdref: ChangeDetectorRef,
private appref: ApplicationRef) {}
ngAfterViewInit() {
this.ngzone.runOutsideAngular( () => {
this.keyupSub = Observable.fromEvent(this.inputElRef.nativeElement, 'keyup')
.debounceTime(1000)
.subscribe(keyboardEvent => {
this.firstName = keyboardEvent.target.value;
this.cdref.detectChanges();
});
this.resizeSub = Observable.fromEvent(window, 'resize')
.throttleTime(200)
.subscribe(e => {
console.log('resize event', e);
this.firstName += '*'; // change something to show it worked
this.cdref.detectChanges();
});
});
}
ngDoCheck() { console.log('cd'); }
ngOnDestroy() {
this.keyupSub .unsubscribe();
this.resizeSub.unsubscribe();
}
}
Plunker
Saya menggunakan ngAfterViewInit()
bukannya ngOnInit()
untuk memastikan bahwa inputElRef
itu didefinisikan.
detectChanges()
akan menjalankan deteksi perubahan pada komponen ini dan anak-anaknya. Jika Anda lebih suka menjalankan deteksi perubahan dari komponen root (yaitu, jalankan pemeriksaan deteksi perubahan penuh) kemudian gunakan ApplicationRef.tick()
. (Saya melakukan panggilan ke ApplicationRef.tick()
dalam komentar di plunker.) Perhatikan bahwa panggilan tick()
akan menyebabkan ngDoCheck()
dipanggil.