Observables : Cancel previous http request on new subscription call
Solution 1
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.
Solution 2
You need to use debounceTime and switchMap operator.
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));
});
Related videos on Youtube
D_S_X
Updated on November 10, 2021Comments
-
D_S_X over 2 years
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.
-
jonrsharpe over 5 yearsLook into switchMap and debounce.
-
Yousef khan over 5 yearsyou can use
unsubscribe()
on subscription for every new change. This way old http request will be cancelled and only latestsubscription
will be valid -
Florian over 5 yearsa great source that could help you in future : learnrxjs.io
-
martin over 5 years
-
-
D_S_X over 5 yearsActually my element is dynamically created in typescript, so i can't add change event listener in template. Whats the way to do this in ts only? (as mentioned in the question i have a change event listener in ts for this)
-
JoshSommer over 5 years@VSharma this is probably out of the scope of the original question. However, how are you creating the element dynamically?
-
JoshSommer over 5 yearsif you have the search bar class in your code you can subscribe to the change event emitter directly. so:
this.searchBar.change.pipe(
instead ofthis.search$.pipe(
this is because Angular's Event Emitter extends RxJS's Subject. I thought I read at one time the Angular team didn't recommend subscribing to Event Emitters directly. But I could be mistaken, you may want to some digging around to confirm this. This isn't a situation I've typically encountered so I haven't had to worry about it. -
chirag sorathiya almost 3 yearsCan we do this in interceptor ?