How to use RxJS to cancel previous HTTP Requests in an Angular Service
In this case, you can simply unsubscribe the previous call using unsubscribe
method. switchMap
is used when we have a higher-order observable.
Just unsubscribe the previous call before making the next one.
fetchCounts(filters?: any): void {
this.loaded = false;
this.apiCall && this.apiCall.unsunscribe(); // Unsubscribe here as well.
this.apiCall = this.api.getCounts(filters).subscribe((results: any) => {
// do something with the returned data
this.loaded = true;
this.apiCall.unsunscribe();
});
}
How to cancel http request in Angular 6?
Long story short:
Easiest way to handle such situations is by using the switchMap operator. What this does is cancel the internal subscription as soon as a new event comes along.
One implementation would be:
class MainComponent {
products: any[];
private _filters$ = new Subject();
constructor(private dataService: DataService_, private filtersService: FiltersService) {
}
ngOnInit() {
this.setProducts()
}
setProducts() {
this._filters$
.switchMap((filters)=> this.dataService.getProducts(filters)) // or .let(switchMap...) if you are using rxjs >5.5
.subscribe(products => this.products = products);
}
onFiltersChange() {
this._filters$.next(this.filtersService.filters);
}
}
Long story:
What happens here is:
When you change filter the onFilterChange is triggered. You then emit the latest filters (inside this.filtersService.filters) through the _filters$ Subject (a subject is almost identical to an EventEmitter).
Back in time during component initialization the ngOnInit method has called setProducts, which has subscribed to the _filters$ subject for future events (none has happened at this point). When an event arrives on _filters$ then we trigger the getProducts method of dataservice, passing it the filters that where contained in the event. We will be waiting on this line until the http call has completed. As soon as it completes the result of the http call will be assigned to the products of the component.
If while we are waiting for the http response to get back, onFiltersChange is fired again, then a new event will arive at the switchMap and it will cancel the previous http request so that it can handle the new event.
This is a very powerful approach as changing a single operator, you can easily change the behavior of your app. For instance, changing switchMap to concatMap will make the request wait for the previous one to complete (will happen serially). Changing it to flatMap will have the same behaviour as the original code you posted (http requests will happen as soon as filters change, without affecting previous ones, order of responses will not predictable) and so on.
Observables : Cancel previous http request on new subscription call
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.
RxJS cancellable HTTP queue
Assuming you have some kind of id
in the item, you could do something like this.
queue.pipe(
groupBy((item) => item.id), // split queue values into independent obs based on grouping key
mergeMap( // process each group obs in parallel
(group$) => group$.pipe(
switchMap((item) => this.httpClient.get(item)) //cancel prev req in the group if still running
)
)
)
.subscribe(console.log);
cheers
Cancelling ongoing Angular $http requests when there's a new request
The solution is to set up the promise, then with each search() cancel it and reinitialize a new one. This will reliably cancel any previous $http():
var canceler = $q.defer();
$scope.search = function() {
canceler.resolve();
canceler = $q.defer();
$http({
method: "GET",
url: "/endpoint.php"
params: {
query: $scope.query
}
timeout: canceler.promise
}).then(function(response) {
$scope.results = response.data;
})
}
RxJS 6 - Angular 6 - Properly canceling current http request if a new one is triggered
Your code is describing the process of sending an http request each time your OnClientUpdate
observable yields. Each yield ends up selecting an observable which represents an http request. switchMap
will subscribe to that http request observable and dispose of it's subscription to any prior http request observable. If that observable's subscription properly implements the disposal of the http request, switchMap
will work as intended.
However, depending on how often OnClientUpdate
can yield, you may want to add a debounce
operation, thus preventing rapid-fire http request and cancellations.
Example - don't spam, cancel all but the latest request, and yield each latest result
:
var latestHttpRequestResult =
trigger
.pipe(debounce(200))
.pipe(switchMap(sendHttpRequestAsObservable));
Related Topics
How to Make New Line or Break in Array
Javascript - Auto Click on a Button on Page Load
Regex Pattern to Match At Least 1 Number and 1 Character in a String
How to Pass Model Data in JavaScript
Creating a Leaderboard in Html/Js
Checking for Null Is Not Working for Ajax Json Data
React - How to Add Dynamic Key/Value Pair to an Object
Determine If String Is in Base64 Using JavaScript
How to Clear the Focus in JavaScript
How to Correctly Use Axios Params With Arrays
How to Have Multiple Buttons of Same Id Value and When Click on Any Button the Pop-Up Should Come
How to Cancel Ongoing Http Requests When There's a New Requests in Angular 6 With Rxjs 6
Display Images in React Using Jsx Without Import
Jquery Validate Phone Number With With Regex
Get the Contents of a Table Row With a Button Click