Обновлено для RC.5
С Angular 2 мы можем отсеивать, используя оператор RxJS debounceTime()
в 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 от Тобиаса Боша, который подтверждает это.) Это можно увидеть, когда вы запускаете плункер, и видите, сколько раз ngDoCheck()
вызывается, когда вы вводите в поле ввода или изменяете размер окна. (Используйте синюю кнопку «x» для запуска плунжера в отдельном окне, чтобы увидеть события изменения размера.)
Более эффективный метод заключается в создании RxJS Observables самостоятельно из событий за пределами «зоны» 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()
вызов.