web-dev-qa-db-fra.com

Comment obtenir un service anti-rebond sur un événement clé d'entrée dans angular2 avec rxjs

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. 

lien plunkr

22
varun

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

43
martin

@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);
    }
}
4

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

3
Simon Dufour

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. 

0
Tim Consolazio