angulartimerrxjsunsubscribe

Rxjs timer restarts after unsubscribe


I started making a simple game to test reflexes. When the red rectangle turns green, the player must click on the figure and the result is displayed. The problem is that after clicking on the rectangle the timer starts again.I use unsubscribe for this, but no results.

Example: https://stackblitz.com/edit/angular-ivy-w8uejd?file=src%2Fapp%2Fapp.component.ts

Code:

HTML

<div (click)="onRegtangleClicked()" class="rectangle" id="rectangle"></div>
<div class="button">
    <button (click)="onStartClicked()" class="btn btn-success">Start</button>
</div>
<p class="text">You score is:  {{time}} (lower is better)</p> 

SCSS

.rectangle {
    position: relative;
    height: 500px;
    width: 100%;
    background-color: rgb(255, 0, 0);
    cursor: pointer;
  }
.button{
    margin-left: 40%;
    margin-top: 2%;
    position: relative;
}
.text{
    font-size: large;
    position: relative;
    margin-left: 40%;
}

typescript

import { Component, OnInit } from '@angular/core';
import { timer } from 'rxjs';

@Component({
  selector: 'app-reflexgame',
  templateUrl: './reflexgame.component.html',
  styleUrls: ['./reflexgame.component.scss'],
})
export class ReflexgameComponent implements OnInit {
  time: number = 0;
  subscription: any;

  constructor() {}

  ngOnInit(): void {}

  onStartClicked() {
    let randomNumber:number = Math.random() * 5;
    setInterval(() => {
      document.getElementById('rectangle')!.style.backgroundColor = 'green';
      this.observableTimer();
    }, randomNumber * 1000);
  }
  onRegtangleClicked() {
    this.subscription.unsubscribe();
  }
  observableTimer() {
    this.subscription = timer(0, 1).subscribe((val) => {
      this.time = val;
    });
  }
}

I don't know where I'm wrong?


Solution

  • The timer is restarting again and again because in the method onStartClicked() you are using setInterval. The logic you define inside an interval is executed continuously every x seconds until you call the clearInterval(theIntervalToClear).

    In your case, you should use a setTimeout to only trigger the logic once after x seconds pass.

    cheers