Оновлено для RC.5
За допомогою Angular 2 ми можемо відмовитись debounceTime()
від використання оператора RxJS на контролі форми, який можна 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
Код, наведений вище, також містить приклад того, як можна зменшити розмір вікна, змінивши розмір подій, про що @albanx запитав у коментарі нижче.
Хоча наведений вище код є, мабуть, кутовим способом його виконання, він не є ефективним. Кожне натискання клавіш і кожна подія зміни розміру, навіть якщо вони знімаються та утримуються, призводить до виявлення змін. Іншими словами, розмикання та дроселювання не впливають на те, як часто змінюються функції виявлення . (Я знайшов коментар GitHub від Tobias Bosch, який підтверджує це.) Ви можете це бачити, коли запускаєте планкер, і ви бачите, скільки разів ngDoCheck()
викликається, коли ви вводите в поле введення або змінюєте розмір вікна. (Використовуйте синю кнопку "x", щоб запустити планкер в окремому вікні, щоб побачити події зміни розміру.)
Більш ефективним прийомом є створення RxJS Спостереження за подіями, поза межами "зони" Angular. Таким чином, виявлення змін не викликається щоразу, коли подія запускається. Потім у ваших методах зворотного виклику підписки вручну запускайте виявлення змін - тобто ви керуєте, коли викликається виявлення змін:
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
Я використовую ngAfterViewInit()
замість того, ngOnInit()
щоб переконатися, що inputElRef
визначено.
detectChanges()
запустить виявлення змін цього компонента та його дочірніх елементів. Якщо ви бажаєте запустити виявлення змін з кореневого компонента (тобто, запустіть повну перевірку виявлення змін), тоді використовуйте ApplicationRef.tick()
натомість. (Я подзвонив ApplicationRef.tick()
у коментарях у планку.) Зауважте, що дзвінок tick()
викликає дзвінок ngDoCheck()
.