Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 380
Mostafa Attia Avatar asked Oct 01 '18 19:10

Mostafa Attia


People also ask

How do you pause a RXJS timer?

The custom observable creates a stream that outputs the number on the stopwatch and is controlled by a separate stream (Here called control$ ). When control$ emits "START", the stopWatch starts, when it emits "STOP", the stopwatch stops, and when it emits "RESET" the stopwatch sets the counter back to zero.

What is timer in RXJS?

Creates an observable that will wait for a specified time period, or exact date, before emitting the number 0.


1 Answers

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.

like image 109
Igor Pomaranskiy Avatar answered Oct 03 '22 20:10

Igor Pomaranskiy