1

I need a timer to be reset which will be called after each activity. So I created a TimerService and setting the timer inside that.

TimerService class:

@Injectable()
export class TimerService {
  timer: Observable<any>;

  constructor() { }

  setTimer(timerVal: number) {
    this.timer = Observable.timer(timerVal);
  }

}

Then I tried to subscribe to it and once the timer has lapsed, it should alert something. I put this logic in AppComponent since I need to subscribe to it in the Rootlevel.

AppComponent class:

export class AppComponent implements OnInit{
  title = 'DataBox';

  constructor(private timerService: TimerService){}

  ngOnInit() {
    this.timerService.setTimer(3000);
    this.timerService.timer.subscribe(t => {
      alert("hello");
    })
  }
}

Now I tried to update the value of the timer from another component, but the it does not affect the timer that is already set.

AnotherComponent class:

export class AnotherComponent implements OnInit{
  users: Observable<any>;    
  constructor(private listUser: ListUserService, private timerService: TimerService) { }

  ngOnInit() {

  }

  updateTimer() {
    this.timerService.setTimer(5000);
  }

}

How do I subscribe to a timerService and update the timer whenever I want? How do I create a Singleton Service and subscribe to the timer? But it should alert only when the timer expires and only once. I'm new to Angular, so pls bear with me.

sand
  • 33
  • 1
  • 6

2 Answers2

1

ForestG is correct, your essential mistake was to overlook javaScript references.

First of all, as ForestG said, if it's a simple interval you are looking for, use the javasScript native interval and clearInterval methods.

If you only want one timer running then this is a more elegant solution in your service. It creates a new interval observable with a conditional cancelation through the "takeUntil" operator.

  cancelTimer$ = new Subject();

  startTimer(interval?: number = 1000) {
    this.cancelTimer$.next();
    const timer = Observable.interval(interval);
    timer.takeUntil(this.cancelTimer$)
      .subscribe((res) => {
        console.log(res)
      },
      err => console.log(err), 
      () => {
        console.log('completed')
      })
  }

The advantage with the takeUnitl is that i causes the observable to throw a "complete" event, which simple ".unsubscribe()" does not. This way you can add a callback to maybe handle the previous timer.

Han Che
  • 8,239
  • 19
  • 70
  • 116
  • i just read that you are asking about a timer and not interval. But the code above should work for both – Han Che May 09 '18 at 12:49
0

The problem is, that in your service you do not reset the timer with setTimer, but create a new one. The subscription on the other component still exists on an Observable, that is still "alive". The only thing you changed is the timer reference, so any new subscritions will subscribe to the new one - but the old subscriptions will still exist.

What you want to do is, to stop the first timer upon overdefinition, and then set the new timer. But that would only solve the first half of the question: your subscritions would be still listening and waiting for the timer. So you have to re-define your application logic, to "finish off" the timers, or, to simply un-sbuscribe from them.

To see, how to stop an observable timer, read this question. Basically, you need to unsubscribe() first in every single subscription and then re-subscribe. I would achive that with a different observable (for instance "alertWhenNewTimerIsSet()" or something) and then re-subscribe to the new value with using the subscriptions themselves.

something like that: timerservice.ts:

 timer: Observable<any>;
 renewSubscriptionsAlert: new EventEmitter<any>();

 setTimer(timerVal: number) {
    timer.renewSubscriptionsAlert.emit(true);
    this.timer = Observable.timer(timerVal);
  }

and in your components:

 mySubscription: any;

 ngOnInit() {
    this.timerService.setTimer(3000);
    this.mySubscription = this.timerService.timer.subscribe(t => {
      alert("hello");
    });
    this.timerService.renewSubscriptionsAlert(alert => {
      myTimerServiceSubscription.unsubscribe();
       this.mySubscription = this.timerService.timer.subscribe(t => {
      alert("hello");
    });
  }

By the way, if you just simply need a timer, you can use the window.setTimeout() method as well.

ForestG
  • 17,538
  • 14
  • 52
  • 86