Ionic time countdown | Function call

First of all thanks for this post:-

I just started working on ionic. This is fantastic to work with this technology. But today I got stuck when I was try to creating a time countdown.

Scenario 1:- Simple countdown : Initialize inside ionViewDidEnter() works great!

.ts file

>  ionViewDidEnter() {   
>     //Call start timer function 
>     this.remainingTime = 50;
>     this.startTimer();
>   }

> startTimer() {   
>     var counter = setTimeout(() => {
>       var time = this.getTimerClock(this.remainingTime);
>       console.log(time);
>       if (this.remainingTime > 0) {
>         this.startTimer();
>         this.remainingTime--;
>       }
>       else {
>         clearInterval(counter);
>       }
>     }, 1000);
>   }

  getTimerClock(inputSeconds: number) {
    var sec_num = parseInt(inputSeconds.toString(), 10);
    this.remainingTime = sec_num; //Define variable
    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;
    }

Result:-

00:00:50
00:00:49
00:00:48...

Scenario 2:- I want to show in html page on the basis of value so I did:-

HTML inside ngFor I am calling function initTimer().

<ion-list *ngFor="let post of posts">
    <span>{{initTimer(post.remainingSeconds)}}</span>
</ion-list>

In .ts file, I add

//Initialize timer function
  initTimer(inputSeconds: number) {
    return this.getTimerClock(inputSeconds);
  }

Then result is:- (7) 02:48:12…

Now there are two problems:-

  1. Counter not working:- Looks like initTimer() calling again and again on every change detection.
  2. Is this good idea to call method inside html page or we have any other better solution?

Welcome to the Ionic Forums.

Dates and times are one of those things that are way more complex than you think, and it’s a really good idea to use well-tested libraries like date-fns to wrangle them. Your getTimerClock function can be replaced by a single one-line format call.

When you’re starting out with Angular, an important rule to try to follow is “don’t call functions from inside interpolation expressions” ({{...}} things). Those get evaluated zillions of times due to change detection. It’s especially critical not to do things that have side effects (like, for example, trying to initialize a timer).

So here is something that should get you started:

import {Component} from '@angular/core';
import {FormControl} from "@angular/forms";
import {interval, Subject} from "rxjs";
import {map, takeUntil, takeWhile} from "rxjs/operators";
import {addSeconds, format} from "date-fns";

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  secs = new FormControl();
  countdownDisplay?: string;
  starter$ = new Subject<void>();

  constructor() {}

  startCountdown(): void {
    this.starter$.next();  // clear pending timers
    let nsecs = this.secs.value;
    interval(1000)
      .pipe(
        takeUntil(this.starter$),
        takeWhile(countup => countup <= nsecs),
        map(countup => {
          let countdown = nsecs - countup;
          let d = new Date();
          d.setHours(0,0,0,0);
          d = addSeconds(d, countdown);
          let fmt = format(d, "HH:mm:ss");
          return fmt;
        }))
      .subscribe(cd => this.countdownDisplay = cd,
        (err) => console.log(err),
        () => alert("ding"));
  }
}
<ion-app>
  <ion-item>
    <ion-label>seconds to count down</ion-label>
    <ion-input [formControl]="secs"></ion-input>
  </ion-item>
  <div *ngIf="countdownDisplay">
    <ion-label>{{countdownDisplay}}</ion-label>
  </div>
  <ion-item button (click)="startCountdown()">start countdown</ion-item>
</ion-app>
2 Likes

Thanks for reply!

But instead of providing new solution, please correct above one.

When you’re starting out with Angular, an important rule to try to follow is “don’t call functions from inside interpolation expressions” ( {{...}} things)

Ok fine, Please tell me how can I pass seconds in current function?
Here function initTimer() calling again and again on its value change, Give me a solution :slight_smile:

I use pipe and now timer start working, please see below changes

HTML:-

<span class=“timer”
{{project.remainingSeconds | getTimerClock}}

What I did:-

<span class="timer" style="display:none"> 
                {{post.remainingSeconds | getTimerClock}}
        </span>

      <span>{{this.timer}}</span>

This is working but not a good idea. How can I improve this?

.ts file

// Define global variable

var remainingTime : any;

@Pipe({

name: ‘getTimerClock’,

pure: true

})

export class post implements OnInit {

public timer: any;

//Initialize timer function

transform(value: number, args?: any): any {

return this.getTimerClock(value);

}

//Timer function

startTimer() {

var counter = setTimeout(() => {      

  this.time = this.getTimerClock(remainingTime); 
  if (remainingTime > 0) {
    this.startTimer();
    remainingTime--;
  }
  else {
    clearInterval(counter);
  }

}, 1000);

}

//Call timer function

getTimerClock(inputSeconds: number) {

remainingTime = parseInt(inputSeconds.toString(), 10);    

var hours = Math.floor(remainingTime / 3600);

var minutes = Math.floor((remainingTime - (hours * 3600)) / 60);

var seconds = remainingTime - (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;

}

}

In console :-
06:39:25
06:39:24
06:39:23…

ON html page showing:- 06:39:25

But how to set these timer(console) values in html page?

@rapropos , please suggest a better solution.

I thought I already did, but you made it clear that that wasn’t what you wanted:

@rapropos Please suggest on this.