7

I'm trying to make a countdown timer for my Ionic2 app, the thing is that I was using this method from now countdown timer but now I have to create the countdown like 30:00 min, what's the better way to do it? Time could change, and if I want to fire something when the countdown it's done I only have to be comparing the time if it's 0, right?

Vega
  • 23,736
  • 20
  • 78
  • 88
StuartDTO
  • 535
  • 4
  • 16
  • 38

3 Answers3

31

You can 'listen' to the timer and trigger the action when the countdown is 0. And to display the timer, use a pipe.

HTML

{{counter | formatTime}}    

TypeScript

  countDown:Subscription;
  counter = 1800;
  tick = 1000;
  ngOnInit() {
    this.countDown = timer(0, this.tick)
      .subscribe(() => --this.counter)
  }
  ngOnDestroy(){
    this.countDown=null;
  }

Pipe

//for MM:SS format
  transform(value: number): string {
    const minutes: number = Math.floor(value / 60);
    return ('00' + minutes).slice(-2) + ':' + ('00' + Math.floor(value - minutes * 60)).slice(-2);
  }

DEMO

//for HH:MM:SS format

transform(value: number): string {
    const hours: number = Math.floor(value / 3600);
    const minutes: number = Math.floor((value % 3600) / 60);
    return ('00' + hours).slice(-2) + ':' + ('00' + minutes).slice(-2) + ':' + ('00' + Math.floor(value - minutes * 60)).slice(-2);
}

DEMO


If you wish to use a service:

Service

 ...
  getCounter(tick) {
    return timer(0, tick) 
  }
 ...

Component

  countDown;
  counter=1800 ;
  tick=1000;

  constructor(private myService: MyService) {
  }

  ngOnInit() {
    this.countDown = this.myService.getCounter(this.tick).subscribe(() => this.counter--);

  }

  ngOnDestroy(){
    this.countDown=null;
  }

Pipe

  ...  
  transform(value: number): string {
    //MM:SS format
    const minutes: number = Math.floor(value / 60);
    return ('00' + minutes).slice(-2) + ':' + ('00' + Math.floor(value - minutes * 60)).slice(-2);

    // for HH:MM:SS
    //const hours: number = Math.floor(value / 3600);
    //const minutes: number = Math.floor((value % 3600) / 60);
    //return ('00' + hours).slice(-2) + ':' + ('00' + minutes).slice(-2) + ':' + ('00' + Math.floor(value - minutes * 60)).slice(-2);

  }

DEMO

Vega
  • 23,736
  • 20
  • 78
  • 88
  • That's the same code of the answer I linked, right? what if I want 30:00 with this I can't do it – StuartDTO Sep 20 '17 at 08:16
  • Plus I can put it on a service and then synchronize it to my page? – StuartDTO Sep 20 '17 at 08:19
  • If you put it in the service, subscribe to this – Vega Sep 20 '17 at 08:43
  • how to 30:00 ? on timer? – StuartDTO Sep 20 '17 at 09:21
  • but with this I can see for example going from 30:00 to 29:59 29:58 ...? – StuartDTO Sep 20 '17 at 09:29
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154877/discussion-between-stuart2041-and-vega). – StuartDTO Sep 20 '17 at 09:54
  • if I get the value from api I got 16:28.564000000000078 why? – StuartDTO Sep 25 '17 at 13:33
  • nono, my api value is something like this : remainingTime:1170.501 – StuartDTO Sep 25 '17 at 13:44
  • cna you join chat one second please? – StuartDTO Sep 25 '17 at 14:43
  • but I'm getting this : Error: InvalidPipeArgument: '1244.533' for pipe 'AsyncPipe' if I do something like this.countDown = 1244.533 – StuartDTO Sep 26 '17 at 15:30
  • Yes but I mean, on my page I'd like to get for example 1244.533 without the --countDown etc because this is on my service... – StuartDTO Sep 26 '17 at 15:40
  • Vega I've edited the question with an example pls help – StuartDTO Sep 26 '17 at 15:43
  • It's not a good idea to update your question because the answer is no more exact. Please put it back. On the other hand, I am not sure what 's going on with the service? – Vega Sep 26 '17 at 15:47
  • I just explained it on chat wish u understand what I'm trying to explain to you – StuartDTO Sep 26 '17 at 17:42
  • the thing is to have this : this.countDown = Observable.timer(0, this.tick) .take(this.counter) .map(() => --this.counter) .do(() => console.log("call here whatever you need")) on service and you on page just have for example this.countDown = myService.getTime() and get time is updating on service Is that possible? – StuartDTO Sep 27 '17 at 12:27
  • 1
    this is how I ended up doing that, perfect man you're good! Thanks for your effort! – StuartDTO Sep 28 '17 at 10:28
  • @Vega Thanks it was helpful, one question how do I stop the timer if it's 0? I mean I did if(this.count === 0) this.sub.unsiscribe() but on the screen is going negative – Skizo-ozᴉʞS Dec 14 '17 at 11:23
  • Is this helpful: https://stackblitz.com/edit/angular-8z6vcu?file=app%2Fapp.component.ts ? – Vega Dec 14 '17 at 11:47
  • Hello @Vega, since I do not have a counter on my app because it is taken syncroniced from services, can I trigger when countdown is 0? I mean, I'm not able to create a variable like "counter" because on my app I have 2 devices that they are syncronicing every X seconds and this counter would change, I can trigger that countDown is 0 or something to call a function? I can do it from .html? – StuartDTO Dec 27 '17 at 10:09
  • Hi @Vega If I want to include hour HH too, how should I change it? – bbusdriver Jan 23 '18 at 23:51
  • @pavilion, I think this should do the trick : https://stackblitz.com/edit/angular-mtij4v – Vega Jan 24 '18 at 07:44
  • 1
    Thanks a lot for this solution! It was exactly the thing I was looking for. But can you remove the spare "}" in the post at the map function. It cost me a lot of time to figure out the mistake I made. @Vega – Oswald Feb 17 '18 at 15:56
  • @Vega may there should be subscriptions for the timer? I think theres more control about that. If you want to change your example with subscriptions I can give you the code. – Oswald Mar 14 '18 at 06:02
  • For the first solution I get: `Template parse errors: The pipe 'formatTime' could not be found ("

    Countdown timer

    {{[ERROR ->]countDown | async | formatTime}}

    "): ng:///AppModule/QuizPageLoop.html@61:12`
    – farahm Oct 11 '18 at 06:48
  • When I am importing: `import { Observable } from 'rxjs/Observable'`. Error occur `Module '"../../../../../../Unnati/WorkSpace/knowledgeUp/node_modules/rxjs/Observable"' has no exported member 'Observable'.ts(2305)` @Vega – Unnati Patadia Apr 04 '20 at 08:13
  • Version: "rxjs": "~6.5.1", I tried to import it in another way `import { Observable, timer } from 'rxjs';` then it thrwos error `Property 'timer' does not exist on type 'typeof Observable'.` @Vega – Unnati Patadia Apr 04 '20 at 08:16
  • @UnnatiPatadia, remove Observable, just timer. – Vega Apr 04 '20 at 08:36
  • @UnnatiPatadia, I updated the post with latest rxjs version – Vega Apr 13 '20 at 01:22
1

Try this for timer:

<h5><span id="time" class="text-primary">00:00</span></h5>

component.ts

import { Component, OnInit, ElementRef, AfterViewInit } from '@angular/core';
import { Observable } from 'rxjs/Rx';

export class AppComponent implements OnInit {

    constructor(private elementRef: ElementRef) { }

    ngOnInit() {
        var callDuration = this.elementRef.nativeElement.querySelector('#time');
        this.startTimer(callDuration);
    }

    startTimer(display) {
        var timer = 1800;
        var minutes;
        var seconds;

        Observable.interval(1000).subscribe(x => {
            minutes = Math.floor(timer / 60);
            seconds = Math.floor(timer % 60);

            minutes = minutes < 10 ? "0" + minutes : minutes;
            seconds = seconds < 10 ? "0" + seconds : seconds;

            display.textContent = minutes + ":" + seconds;

            --timer;
            if (timer < 0) {
                 console.log('timer is ended');
            }
        })
    }
}
Shubham Azad
  • 677
  • 8
  • 22
Chandru
  • 9,360
  • 3
  • 32
  • 50
  • I'll test this answer, to check what is more efficient, thanks @Chandru, by the way if instead of "timer" I have an api call that returns this : remainingTime:1244.529 with your option is possible to do that? – StuartDTO Sep 20 '17 at 10:46
  • Yeah it's possible using this code .. set the remainingTime:1244.529 instead of 'timer' then the timer start with 20.44 – Chandru Sep 20 '17 at 10:50
  • and if I have this on a service, it can update the view ? I mean the countdown is running but if I do an api call and returns a different remaingingTime I have to update it, it is possible? – StuartDTO Sep 20 '17 at 12:44
  • if you want to help me with that problem come on this [question](https://stackoverflow.com/questions/46338921/upload-a-view-from-service-every-x-seconds-ionic2) – StuartDTO Sep 21 '17 at 09:27
  • chandru with your answer I can have the observable stuff in the service, and from page get the value? I mean service have the observable and on page I have the "timer" (in your code)? – StuartDTO Sep 27 '17 at 12:38
  • Excellent thanks after spending hours. Simple quick responsive – Rajat.r2 Oct 16 '20 at 15:24
  • After time up, timer and observer is still running how can I unsubscribe that observer ? – Rajat.r2 Oct 16 '20 at 15:34
-1
maxtime: any=30

  StartTimer(){
    this.timer = setTimeout(x => 
      {
          if(this.maxTime <= 0) { }
          this.maxTime -= 1;

          if(this.maxTime>0){
            this.hidevalue = false;
            this.StartTimer();
          }

          else{
              this.hidevalue = true;
          }

      }, 1000);


  }