Aggiornato per RC.5
Con Angular 2 possiamo rimbalzare usando l'operatore RxJS sull'osservabile di debounceTime()
un form control valueChanges
:
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
Il codice sopra include anche un esempio di come limitare gli eventi di ridimensionamento della finestra, come richiesto da @albanx in un commento qui sotto.
Sebbene il codice sopra sia probabilmente il modo angolare di farlo, non è efficiente. Ogni sequenza di tasti e ogni evento di ridimensionamento, anche se sono rimbalzati e limitati, provoca il rilevamento delle modifiche in esecuzione. In altre parole, il debouncing e il throttling non influiscono sulla frequenza con cui viene eseguito il rilevamento delle modifiche . (Ho trovato un commento GitHub di Tobias Bosch che lo conferma.) Puoi vederlo quando esegui il plunker e vedi quante volte ngDoCheck()
viene chiamato quando digiti nella casella di input o ridimensioni la finestra. (Usa il pulsante blu "x" per eseguire il plunker in una finestra separata per vedere gli eventi di ridimensionamento.)
Una tecnica più efficiente è quella di creare osservabili RxJS dagli eventi, al di fuori della "zona" di Angular. In questo modo, il rilevamento delle modifiche non viene chiamato ogni volta che viene generato un evento. Quindi, nei metodi di callback di sottoscrizione, attiva manualmente il rilevamento delle modifiche, ovvero controlli quando viene chiamato il rilevamento delle modifiche:
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
Uso ngAfterViewInit()
invece di ngOnInit()
assicurarsi che inputElRef
sia definito.
detectChanges()
eseguirà il rilevamento delle modifiche su questo componente e sui relativi figli. Se preferisci eseguire il rilevamento delle modifiche dal componente radice (ovvero, eseguire un controllo completo del rilevamento delle modifiche), utilizza ApplicationRef.tick()
invece. (Ho inserito una chiamata ApplicationRef.tick()
nei commenti nel plunker.) Nota che la chiamata tick()
verrà ngDoCheck()
chiamata.