J'essaie d'appeler un service sur un événement de saisie d'entrée.
Le HTML
<input placeholder="enter name" (keyup)='onKeyUp($event)'>
Ci-dessous la fonction onKeyUp()
onKeyUp(event) {
let observable = Observable.fromEvent(event.target, 'keyup')
.map(value => event.target.value)
.debounceTime(1000)
.distinctUntilChanged()
.flatMap((search) => {
// call the service
});
observable.subscribe((data) => {
// data
});
}
L’onglet réseau du navigateur a révélé que la fonction key-up est appelée à chaque événement key-up (comme il est censé le faire), mais j’essaie d’obtenir un temps d’abattement de 1 seconde entre chaque appel de service. En outre, l'événement est déclenché si je déplace le déplacement de la flèche.
Donc, la chaîne est vraiment correcte, mais le problème est que vous créez un observable et que vous vous y abonnez à chaque événement keyup
. C'est pourquoi il imprime la même valeur plusieurs fois. Il y a simplement plusieurs abonnements, ce qui n'est pas ce que vous voulez faire.
Il y a évidemment plus de façons de le faire correctement, par exemple:
@Component({
selector: 'my-app',
template: `
<div>
<input type="text" (keyup)='keyUp.next($event)'>
</div>
`,
})
export class App implements OnDestroy {
public keyUp = new Subject<KeyboardEvent>();
private subscription: Subscription;
constructor() {
this.subscription = this.keyUp.pipe(
map(event => event.target.value),
debounceTime(1000),
distinctUntilChanged(),
mergeMap(search => of(search).pipe(
delay(500),
)),
).subscribe(console.log);
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
Voir votre démo mise à jour: http://plnkr.co/edit/mAMlgycTcvrYf7509DOP
Jan 2019: Mise à jour pour RxJS 6
@marlin a donné une excellente solution et cela fonctionne très bien dans angular 2.x mais avec angular 6, ils ont commencé à utiliser la version 6.0 de rxjs.
import {Component} from '@angular/core';
import {Observable, of, Subject} from 'rxjs';
import {debounceTime, delay, distinctUntilChanged, flatMap, map, tap} from 'rxjs/operators';
@Component({
selector: 'my-app',
template: `
<div>
<input type="text" (keyup)='keyUp.next($event)'>
</div>
`,
})
export class AppComponent {
name: string;
public keyUp = new Subject<string>();
constructor() {
const subscription = this.keyUp.pipe(
map(event => event.target.value),
debounceTime(1000),
distinctUntilChanged(),
flatMap(search => of(search).pipe(delay(500)))
).subscribe(console.log);
}
}
Je vous suggère de consulter le didacticiel Angular2 qui présente un exemple explicite et clair de quelque chose de similaire à ce que vous demandez.
https://angular.io/docs/ts/latest/tutorial/toh-pt6.html#!#observables
Eh bien, voici un debouncer de base.
ngOnInit ( ) {
let inputBox = this.myInput.nativeElement;
let displayDiv = this.myDisplay.nativeElement;
let source = Rx.Observable.fromEvent ( inputBox, 'keyup' )
.map ( ( x ) => { return x.currentTarget.value; } )
.debounce ( ( x ) => { return Rx.Observable.timer ( 1000 ); } );
source.subscribe (
( x ) => { displayDiv.innerText = x; },
( err ) => { console.error ( 'Error: %s', err ) },
() => {} );
}
}
Si vous configurez les deux enfants de la vue indiquée (l'entrée et l'affichage), vous verrez que l'anti-rebond fonctionne. Vous ne savez pas si cela ne fait rien de votre fait, mais cette forme de base est (à ma connaissance) le moyen le plus simple d’abattre des rebonds, j’utilise assez ce point de départ, l’ensemble du texte intérieur n’est qu’un exemple, il peut faire un appel de service ou autre chose dont vous avez besoin.