Observables : Cancel previous http request on new subscription call

D_S_X picture D_S_X · Nov 22, 2018 · Viewed 16k times · Source

I am working on a search functionality for my project. Once the user types anything on the search bar; on any change in search text I'll be sending the text to backend for validation and receive a response (error or no error in text):

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

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

Now as the user continuously types in the search bar, multiple validation responses are incoming through back-end. However, on any new change only the latest subscription is valid and any previous call to api is useless.

Is there any way I can cancel the previous subscription on any new call to api using subscribe?

Note: It might seem possible to just wait for all responses but I am also going to display the responses below the search bar(showing a loader till then). So, rather than transition between various response states I want loader to keep loading until the latest response is available.

Answer

JoshSommer picture JoshSommer · Nov 22, 2018

I would use a subject to keep everything reactive. In your template html listen to change events and emit a new value to the subject.

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

then in your component:

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

The switchMap will cancel any HTTP request that hasn't completed if a new value is emitted through the subject. You can play with the debouneTime to see what feels right for you. Lastly, make sure you unsubscribe from your subject in the ngOnDestroy, this will prevent any memory links and keep everything nice and perfromant.:

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

Suresh's answer has a distinctUntilChanged() which is an excellent addition to the solution. I'm adding it but want to give credit to his answer below. This is a benefit because if I search for egg the request is made. But then I add an s the end of egg and change my mind before the debounce is completed another duplicate HTTP post with a search of egg will not be made.