Search code examples
angularangular6rxjs6

pause/resume a timer Observable


I'm building a simple stopwatch with angular/rxjs6, I can start the timer but I can't pause/resume it.

  source: Observable<number>;
  subscribe: Subscription;

  start() {
    this.source = timer(0, 1000);
    this.subscribe = this.source
      .subscribe(number => {
        this.toSeconds = number % 60;
        this.toMinutes = Math.floor(number / 60);
        this.toHours = Math.floor(number / (60 * 60));

        this.seconds = (this.toSeconds < 10 ? '0' : '') + this.toSeconds;
        this.minutes = (this.toMinutes < 10 ? '0' : '') + this.toMinutes;
        this.hours = (this.toHours < 10 ? '0' : '') + this.toHours;
    });
  }

  pause() {
    this.subscribe.unsubscribe(); // not working
  }

after doing lot of searching, I found that I should use switchMap operator to accomplish that, but I'm new to rxjs and don't know how to do it the right way.

Any help would be much appreciated.


Solution

  • I've faced the same problem today (when implementing Tetris clone with Angular). Here is what I ended up with:

    import { Subject, timer } from 'rxjs';
    
    export class Timer {
      private timeElapsed = 0;
      private timer = null;
      private subscription = null;
    
      private readonly step: number;
    
      update = new Subject<number>();
    
      constructor(step: number) {
        this.timeElapsed = 0;
        this.step = step;
      }
    
      start() {
        this.timer = timer(this.step, this.step);
        this.subscription = this.timer.subscribe(() => {
          this.timeElapsed = this.timeElapsed + this.step;
          this.update.next(this.timeElapsed);
        });
      }
    
      pause() {
        if (this.timer) {
          this.subscription.unsubscribe();
          this.timer = null;
        } else {
          this.start();
        }
      }
    
      stop() {
        if (this.timer) {
          this.subscription.unsubscribe();
          this.timer = null;
        }
      }
    }
    

    And in my game service I use it like this:

      init() {
        this.timer = new Timer(50);
        this.timer.start();
        this.timer.update.subscribe(timeElapsed => {
          if (timeElapsed % 1000 === 0) {
            this.step(); // step() runs one game iteration
          }
        });
      }
    
      togglePause() {
        this.timer.pause();
      }
    

    N.B.: I'm new to Angular/RxJS, so I'm not sure if the code above is good. But it works.