89

How to cancel a HTTPRequest in Angular 2?

I know how to reject the request promise only.

return new Promise((resolve, reject) => {
    this.currentLoading.set(url, {resolve, reject});

    this.http.get(url, {headers: reqHeaders})
        .subscribe(
            (res) => {
                res = res.json();

                this.currentLoading.delete(url);
                this.cache.set(url, res);

                resolve(res);
            }
        );
});
Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
tom10271
  • 4,222
  • 5
  • 33
  • 62

6 Answers6

100

You can use the following simple solution:

if ( this.subscription ) {
   this.subscription.unsubscribe();
}
this.subscription = this.http.get( 'awesomeApi' )
 .subscribe((res)=> {
  // your awesome code..
})
rostamiani
  • 2,859
  • 7
  • 38
  • 74
ErvTheDev
  • 4,390
  • 3
  • 16
  • 20
88

You can call unsubscribe

let sub = this.http.get(url, {headers: reqHeaders})
            .subscribe(
                (res) => {
                    res = res.json();

                    this.currentLoading.delete(url);
                    this.cache.set(url, res);

                    resolve(res);
                }
            );

sub.unsubscribe();

More info here: http://www.syntaxsuccess.com/viewarticle/angular-2.0-and-http

TGH
  • 38,769
  • 12
  • 102
  • 135
  • 1
    This answer is not longer valid in beta.15. There is no `unsubscribe` method in Observable now. – tom10271 Apr 25 '16 at 07:52
  • 1
    `unsubscribe` was replaced by `dispose`. – Menello Jun 10 '16 at 15:19
  • 3
    I'm using RC.5 of Angular2, and `unsubscribe` is present (version 5.0.0-beta.6 of rxjs). Perhaps it was restored since the comments were made? Not sure where the discrepancy is coming from. – Dawson Toth Aug 18 '16 at 15:12
  • @DawsonToth Angular 2 team hasn't updated rxjs from a long time, it will be updated in RC6 – Godfather Aug 26 '16 at 18:18
  • could somebody provide a live example and we close the question about `unsubscribe ` / `dispose ` – Stepan Suvorov Sep 14 '16 at 06:45
  • 1
    What is unsubscribing all of a sudden stops cancelling the request? What can be the problem? – Bruno Santos Feb 12 '19 at 21:18
  • This is actually not correct. The service will unsubscribe before it even completes. Not sure why this was marked as correct answer by so many. – GeoRover May 06 '20 at 20:52
10

You can use SwitchMap on the observable which will cancel any previous request's responses and only request the latest:

https://www.learnrxjs.io/operators/transformation/switchmap.html

Ben Taliadoros
  • 7,003
  • 15
  • 60
  • 97
9

A little late for the party, but here is my take:

import { Injectable } from '@angular/core'
import { Http } from '@angular/http'
import { Observable } from 'rxjs/Observable'
import { Subscriber } from 'rxjs/Subscriber'

@Injectable ()
export class SomeHttpServiceService {
  private subscriber: Subscriber<any>
  constructor(private http: Http){ }

  public cancelableRequest() {
    let o = new Observable(obs => subscriber = obs)
    return this.http.get('someurl').takeUntil(o)
      .toPromise() //I dont like observables
      .then(res => {
        o.unsubscribe
        return res
      })
  }
  public cancelRequest() {
    subscriber.error('whatever')
  }
}

This allows you to manually cancel a request. I sometimes end up with an observable or promise that will make changes to a result on the page. If the request was initiated automatically (user didn't type anyting in a field for x millis) being able to abort the request is nice (user is suddenly typing something again)...

takeUntil should also work with a simple timeout (Observable.timer) if that is what you are looking for https://www.learnrxjs.io/learn-rxjs/operators/filtering/takeuntil

Ron Strauss
  • 60
  • 1
  • 7
clearfix
  • 467
  • 1
  • 5
  • 10
  • 3
    Why don't u like observables? For http it is the same like promise, but also has error and complete – Mick Aug 31 '17 at 12:57
  • 1
    @Mick, I think clearfix was just accommodating the OP's preference for promises, not expressing his/her opinion. #theSpiritOfStackOverflow – Rap Nov 10 '17 at 15:53
6

Use switchMap [docs], which will cancel all in-flight requests and use only the latest.

get(endpoint: string): Observable<any> {
        const headers: Observable<{url: string, headers: HttpHeaders}> = this.getConfig();
        return headers.pipe(
            switchMap(obj => this.http.get(`${obj.url}${endpoint}`, { headers: obj.headers, params: params }) ),
            shareReplay(1)
        );
    }

shareReplay will emit the latest value for any late subscribers.

Ian
  • 2,898
  • 1
  • 27
  • 29
  • 3
    how to do it if I do't have any observable link your `headers`. I have http call made on click of button but from the docs, I can only use `switchMap` on observable – rainversion_3 Mar 04 '20 at 15:04
2

This is a great thread, and I have a little more info to provide. I have an API call that could potentially go on for a very long time. So I needed the previous request to cancel with a timeout. I just figured out today that I can add a timeout operator to the pipe function. Once the timeout completes its count, that will cancel the previous HTTP request.

Example...

return this.exampleHttpRequest()
  .pipe(
    timeout(3000),
    catchError(err => console.log(error)
)
Andrew Gremlich
  • 353
  • 4
  • 7