Ranjith Varatharajan
Ranjith Varatharajan

Reputation: 1694

Reset subscription inside a timer

Scenario:

I have a api call (this.service.checkStatus(this.movieForm.value.movie)) which should be consumed at every 60 seconds. and between the 60 second, I need to show a 1 second counter (something like x seconds until next call). So I'm using two timer (source$ & source2$). But the problem with the below code is source2$ doesn't stops after a new api call, instead a new subscription is created for every 60 seconds. The old source2$ subscription is still incrementing by 1 and the new one starts with 0 and making a mess. How can I fix this?

Below is my code.

Code:

source$ = timer(0, 60000); // every 60 seconds it will emit
source2$ = timer(0, 1000); // every 1 second it will emit
...
getStatus() {
    this.apiSubscription$ = this.source$.subscribe(() => {

      // I need to reset this timersubscription. so that the val always starts from 0

      this.timerSubscription$ = this.source2$.subscribe((val: number) => {
          this.timer = 60 - val;
          this.progress.nativeElement.style.width = (val / 60) * 100 + '%';
        });
      this.service.checkStatus(this.movieForm.value.movie)
        .pipe(take(1))
        .subscribe(res => {
          const response: any = res;
          if (!response.status) {
            // do stuff 1
          } else {
            // do stuff 2
            this.apiSubscription$.unsubscribe();
          }
        });
    });
  }

Upvotes: 0

Views: 521

Answers (1)

bryan60
bryan60

Reputation: 29355

this is part of why nested subscribes are an anti pattern and should be avoided... you want to be using the proper operators that handle subscribing and unsubscribing for you:

this.apiSubscription$ = source1$.pipe(
  switchMap(() => { // switchMap subscribes to new inner subscriptions and cancels previous ones
    const counter$ = source2$.pipe(
      tap(timer => { // tap lets you produce side effects
        this.timer = 60 - timer;
        this.progress.nativeElement.style.width = (timer / 60) * 100 + '%';
      })
    )
    const status$ = this.service.checkStatus(this.movieForm.value.movie).pipe(
      first(), // first is more semantic IMO
      tap(response => {
        if (!response.status) {
          // do stuff 1
        } else {
          // do stuff 2
        }
      })
    )
    return combineLatest(counter$, status$); // combine observables
  }),
   // takeWhile will end your subscription for you if the condition is false
  takeWhile(([timer, statusResponse]) => !!statusResponse.status)
).subscribe() 

Upvotes: 1

Related Questions