Search code examples
angularhttprxjsobservableswitchmap

How to cancel http request with switchMap?


I want to cancel the previous http request if i made the new http request to server but it is not working as expected to me.

i want to cancel the request if some value got changed in the function i mean if the value change the old request should cancel and new one should create for this i have done this

1) Created a subject - The thing that will be watched by the observable
public stringVar = new Subject<string>();

2) Create an observable to watch the subject and send out a stream of updates (You will subscribe to this to get the update stream)

public stringVar$ = this.stringVar.asObservable()

3)In a particular function i am getting the value as an argument so i perform these steps

  testFunction(value){
      this.stringVar.next(listValueSelected);
      this.testOutput = this.stringVar$.pipe(
             switchMap(() => {
                return  this.teseService.getEntries(val_one, val_two,val_three);
           })
         )
         this.testOutput.subscribe(result => console.log(`${result}`));
    } 

The request is cancelble when value is going to change but getting vary strange behaviour first time only one request is mode but when i click second time it calling api two time and this will go on .What is wrong with my code ?

in the component.ts

export class TestComponent {
    testOutput :Observable<any>;
    stringVar =  new Subject<number>();
    stringVar$ = this.stringVar.asObservable();

 testResult(selectedValue) {
       this.stringVar.next(selectedValue);
       this.stringVar$.subscribe(data => {
      });
       this.testOutput = this.stringVar$.pipe(
             switchMap(() => {
                return  this.testService.getTestEntries(this.x,this.y,this.z);
           })
         )
         this.testOutput.subscribe(result => console.log(`${result}`));
    }

}

in the service file

getTestEntries(x, y,selectedValue): Observable<any>{
        let apiUrl = selectedValue=='3'?this.baseUrl1:this.baseUrl ;

        return this.http.post(apiUrl,obj).map((response: Response) => {

              return response;
        })
      }

i want to cancel my old request and create new if the value "selectedValue" changed in the component.


Solution

  • I believe that you call your method testResult(selectedValue) whenever you click the button, so this will create new Observable and subscribe to it as you click the button and call the method. These new Observable subscriptions are causing multiple network requests.

    Ideally you want to subscribe to the stringVar$ only once in the constructor and when something changes just emit updated value in the stringVar Subject. Since Observable subscription is only one and already existing, it will catch emitted new value and will create new http request with the help of switchMap operator.

    FYI you have correctly chosen switchMap operator. It will discard latest network call if new event arrives in the meantime.

    This is your working example:

    export class TestComponent {
      testOutput: Observable<any>;
      stringVar = new Subject<number>();
      stringVar$ = this.stringVar.asObservable();
    
      constructor() {
        this.testOutput = this.stringVar$.pipe(
          switchMap(() => {
            return this.testService.getTestEntries(this.x, this.y, this.z);
          }),
        );
        this.testOutput.subscribe((result) => console.log(`${result}`));
      }
    
      testResult(selectedValue) {
        this.stringVar.next(selectedValue);
      }
    }