web-dev-qa-db-fra.com

Observables: Annuler la demande http précédente lors du nouvel appel d'abonnement

Je travaille sur une fonctionnalité de recherche pour mon projet. Une fois que l'utilisateur tape quoi que ce soit sur la barre de recherche; sur tout changement dans le texte de recherche, je vais envoyer le texte au backend pour validation et recevoir une réponse (erreur ou pas d'erreur dans le texte):

this.searchBar.on('change', () => {

    http.post('api_link', {searchText: 
       this.serachBar.searchText}).subscribe(resp => {
            this.resp = resp['Result'];
       });
    })

Maintenant que l'utilisateur tape continuellement dans la barre de recherche, plusieurs réponses de validation arrivent via le back-end. Cependant, à chaque nouvelle modification, seul le dernier abonnement est valide et tout appel précédent à api est inutile.

Existe-t-il un moyen d'annuler l'abonnement précédent lors de tout nouvel appel à l'api en utilisant abonnement?

Remarque: il peut sembler possible d'attendre toutes les réponses, mais je vais également afficher les réponses sous la barre de recherche (montrant un chargeur jusque-là). Donc, plutôt que de faire la transition entre différents états de réponse, je veux que le chargeur continue de se charger jusqu'à ce que la dernière réponse soit disponible.

7
V_S_X

J'utiliserais un sujet pour que tout reste réactif. dans votre modèle html écoutez les événements de changement et émettez une nouvelle valeur au sujet.

 <searchBar (change)="search$.next($event.target.value)" />

puis dans votre composant:

  this.subscription = this.search$.pipe(
     debounceTime(800), 
     distinctUntilChanged(),
     switchMap(searchText=>http.post('api_link', {searchText})
    }).subscribe(response=>{
       this.response = response.
    });

Le switchMap annulera toute demande HTML qui ne s'est pas terminée si une nouvelle valeur est émise via le sujet. vous pouvez jouer avec le debouneTime pour voir ce qui vous convient. Enfin, assurez-vous de vous désinscrire de votre sujet dans le ngOnDestroy, cela empêchera tout lien mémoire et gardera tout Nice et perfromant .:

ngOnDestroy(){
   this.subscription. unsubscribe();
}

Suresh's answer a une distinctUntilChanged() qui est un excellent ajout à la solution. Je l'ajoute, mais je veux donner du crédit à sa réponse ci-dessous. C'est un avantage car si je recherche Egg la demande est faite. mais ensuite j'ajoute un s la fin d'Egg et je change d'avis avant que le debounce soit terminé, un autre post HTTP en double avec une recherche d'Egg ne sera pas fait.

2
JoshSommer

Vous devez utiliser debounceTime et l'opérateur switchMap.

this.searchBar.on('change', () => {

    of(this.serachBar.searchText).pipe(
       debounceTime(400),
       distinctUntilChanged(),
       switchMap((text)=> {
          return http.post('api_link', {searchText: text}).map(resp => {
            return resp['Result'];
          });
        });
    ).subscribe(response=> console.log(response));

});
0
Suresh Kumar Ariya