Ionic 2: Simple Countdown Timer

Want a simple countdown timer for your Ionic 2 app? Here's a quick one I made. It's not fancy, but it works and does the job it needs to do for my app.

Default Alt Text

Default Alt Text

TL;DR

Here's a plunkr, feel free to use it.

For the timer you'll need to make 3 files:

  • timer.html - the timer html layout
  • timer.ts - the timer code
  • itimer.ts - the interface description for the timer

Organise these however you want directory wise. Whatever.

1) timer.html:

<ion-card *ngIf="timer">
    <ion-item class="no-bottom-border item">
        <button ion-button *ngIf="timeInSeconds && timeInSeconds > 0" large full clear class="timer-button timer-text">{{timer.displayTime}}</button>
    </ion-item>
    <ion-item class="no-bottom-border" *ngIf="timeInSeconds && timeInSeconds > 0">
        <button ion-button icon-left clear color="danger" small (click)="initTimer()" item-left *ngIf="!timer.runTimer && (timer.hasStarted || timer.hasFinished) || timer.hasFinished">
            <ion-icon name="refresh"></ion-icon>
            Reset
        </button>
        <button ion-button icon-left clear small color="primary" (click)="pauseTimer()" item-right *ngIf="timer.runTimer && timer.hasStarted && !timer.hasFinished">
            <ion-icon name="pause"></ion-icon>
            Pause
        </button>      
        <button ion-button icon-left clear small color="primary" (click)="resumeTimer()" item-right *ngIf="!timer.runTimer && timer.hasStarted && !timer.hasFinished">
            <ion-icon name="play"></ion-icon>
            Resume
        </button>      
        <button ion-button icon-left clear small color="primary" (click)="startTimer()" item-right *ngIf="!timer.hasStarted">
            <ion-icon name="play"></ion-icon>
            Start
        </button>            
    </ion-item>
</ion-card>  

<style>
  .timer-button {
    font-size: 5rem !important;
    height: 1em !important;
  }
  
  .no-bottom-border.item .item-inner {
      border-bottom: none !important;
  }
</style>

2) timer.ts:

import {Component, Input} from '@angular/core';
import {Timer} from './itimer';


@Component({
    selector: 'timer',
    templateUrl: 'app/timer.html'
})
export class TimerComponent {

    @Input() timeInSeconds: number;
    public timer: ITimer;

    constructor() {
    }

    ngOnInit() {
        this.initTimer();
    }

    hasFinished() {
        return this.timer.hasFinished;
    }

    initTimer() {
        if(!this.timeInSeconds) { this.timeInSeconds = 0; }

        this.timer = <ITimer>{
            seconds: this.timeInSeconds,
            runTimer: false,
            hasStarted: false,
            hasFinished: false,
            secondsRemaining: this.timeInSeconds
        };

        this.timer.displayTime = this.getSecondsAsDigitalClock(this.timer.secondsRemaining);
    }

    startTimer() {
        this.timer.hasStarted = true;
        this.timer.runTimer = true;
        this.timerTick();
    }

    pauseTimer() {
        this.timer.runTimer = false;
    }

    resumeTimer() {
        this.startTimer();
    }

    timerTick() {
        setTimeout(() => {
            if (!this.timer.runTimer) { return; }
            this.timer.secondsRemaining--;
            this.timer.displayTime = this.getSecondsAsDigitalClock(this.timer.secondsRemaining);
            if (this.timer.secondsRemaining > 0) {
                this.timerTick();
            }
            else {
                this.timer.hasFinished = true;
            }
        }, 1000);
    }

    getSecondsAsDigitalClock(inputSeconds: number) {
        var sec_num = parseInt(inputSeconds.toString(), 10); // don't forget the second param
        var hours   = Math.floor(sec_num / 3600);
        var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
        var seconds = sec_num - (hours * 3600) - (minutes * 60);
        var hoursString = '';
        var minutesString = '';
        var secondsString = '';
        hoursString = (hours < 10) ? "0" + hours : hours.toString();
        minutesString = (minutes < 10) ? "0" + minutes : minutes.toString();
        secondsString = (seconds < 10) ? "0" + seconds : seconds.toString();
        return hoursString + ':' + minutesString + ':' + secondsString;
    }
    
}

3) itimer.ts:

export interface ITimer {
  seconds: number;
  secondsRemaining: number;
  runTimer: boolean;
  hasStarted: boolean;
  hasFinished: boolean;
  displayTime: string;
}

4) Then in your page class:

Then, you can shove them on a page like so:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { ViewChild } from '@angular/core';
import { TimerComponent } from './timer';

@Component({
  selector: 'page-home',
  templateUrl: 'app/home.page.html'
})
export class HomePage {
  
  @ViewChild(TimerComponent) timer: TimerComponent;

  appName = 'Ionic App';

  constructor(private navController: NavController) { 
  }

  ngOnInit() {
    setTimeout(() => {
      this.timer.startTimer();
    }, 1000)
  }

}

5) ...and the page html:

<timer #timer timeInSeconds="60"></timer>

or if you want to bind the value to a variable in your page, use square brackets:

<timer #timer [timeInSeconds]="myVariableNameHere"></timer>

6) Finally:

In your app.module.ts, make sure you declare your timer component e.g.:

import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';

import { AppComponent } from './app.component';
import { HomePage } from './home.page';
import { TimerComponent } from './timer';

@NgModule({
  imports: [ IonicModule.forRoot(AppComponent) ],
  declarations: [ AppComponent, HomePage, TimerComponent ],
  entryComponents: [ HomePage ],
  bootstrap: [ IonicApp ]
})
export class AppModule { }

7) Extra stuff:

If you want to know when the timer is finished, e.g. to enable a button on a form, include an element reference to the timer with its id, then bind the disabled input property of the button like so:

<timer #timer [timeInSeconds]="10"></timer>
 
  // some more html form...

<button [disabled]="timer && !timer.hasFinished()">
  Save
</button>
import {Timer} from "./timer.ts"
import {ViewChild} from '@angular/core';
 
@Component({
  templateUrl: "home.html"
})
export class HomePage {
  @ViewChild(TimerComponent) timer: TimerComponent;
 
  constructor() {}
  //....
}

BOOM!

Hope this helps. Comment if unclear. Thanks!

Comments: