J'ai un composant qui encapsule un autre composant <inner-component>
et se lie à l'événement personnalisé InnerComponent.innerChanged()
. Je souhaite faire une bulle en utilisant une propriété @output
, mais je souhaite également réduire les résultats.
Comment utiliser RxJS
.debounce()
ou .debounceTime()
pour le faire?
Quelque chose comme ça:
import {Component, Output, EventEmitter} from 'angular2/core';
import 'rxjs/add/operator/debounce';
import 'rxjs/add/operator/debounceTime';
@Component({
selector: 'debounced-component',
template: `
<div>
<h1>Debounced Outer Component</h1>
// export class InnerComponent{
// @Output() innerChanged: new EventEmitter<string>();
// onKeyUp(value){
// this.innerChanged.emit(value);
// }
// }
<input #inner type="text" (innerChange)="onInnerChange(inner.value)">
</div>
`
})
export class DebouncedComponent {
@Output() outerValueChanged: new EventEmitter<string>();
constructor() {}
onInnerChange(value) {
this.outerValuedChanged.emit(value); // I want to debounce() this.
}
}
Pour réduire les valeurs, vous pouvez utiliser un sujet. Un sujet est à la fois observable et observateur. Cela signifie que vous pouvez le traiter comme un observable et lui transmettre des valeurs.
Vous pouvez en tirer parti pour transmettre les nouvelles valeurs du composant interne à celui-ci et le supprimer de cette manière.
export class DebouncedComponent {
@Output() outerValueChanged: new EventEmitter<string>();
const debouncer: Subject = new Subject();
constructor() {
// you listen to values here which are debounced
// on every value, you call the outer component
debouncer
.debounceTime(100)
.subscribe((val) => this.outerValuedChanged.emit(value));
}
onInnerChange(value) {
// send every value from the inner to the subject
debouncer.next(value);
}
}
C'est un pseudo-code non testé. Vous pouvez voir un exemple de travail du concept ici ( http://jsbin.com/bexiqeq/15/edit?js,console ). C'est sans angularité mais le concept reste le même.
Mise à jour: Pour les versions plus récentes de Angular, vous aurez peut-être besoin d'une modification légère: changez debouncer.debounceTime(100)
est remplacé par debouncer.pipe(debounceTime(100))
constructor() {
// you listen to values here which are debounced
// on every value, you call the outer component
debouncer
.pipe(debounceTime(100))
.subscribe((val) => this.outerValuedChanged.emit(value));
}
Voici un exemple de classe fonctionnant avec toutes les importations nécessaires, Angular 4+, TypeScript et tslint-friendly :) pensaient que cela pourrait aider certaines personnes à la recherche de ce que je cherchais il y a un instant!
import { Component, Input, Output, EventEmitter, ViewChild, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/debounceTime';
@Component({
selector: 'app-searchbox',
template: `
<input type="text" autocomplete="off" [(ngModel)]="query" [placeholder]="placeholder" (change)="onInputChange($event)">
`
})
export class SearchboxComponent implements OnDestroy {
@Input() debounceTime = 500;
@Output() change = new EventEmitter<string>();
query = '';
placeholder = 'Search...';
results;
debouncer = new Subject<string>();
subs = new Array<Subscription>();
constructor() {
this.subs.Push(this.debouncer.debounceTime(this.debounceTime).subscribe(
(value: string) => { this.change.emit(value); },
(error) => { console.log(error); }
));
}
onInputChange(event: any) {
this.debouncer.next(event.target.value);
}
ngOnDestroy() {
for (const sub of this.subs) {
sub.unsubscribe();
}
}
}