Mr. A
Mr. A

Reputation: 111

Return value from setInterval() function called from html

I want to return the value from setInterval() function which is called from html file.

I know that the actual function is not returning anything and that's why the value is not being shown. But how can I return the value from an asynchronous function.

Here's the code:

.ts:

data = [
    {
      game: "A vs B",
      timeLeft: 123456
    },
    {
      game: "C vs D",
      timeLeft: 342514
    },
    {
      game: "A vs C",
      timeLeft: 654789
    },
    {
      game: "B vs D",
      timeLeft: 978456
    }
  ];
  clearTimeIntervalVar: any;

countdownTime(seconds: number) {
    let hr: any = Math.floor(seconds / 3600);
    let min: any = Math.floor((seconds % 3600) / 60);
    let sec: any = Math.floor((seconds % 3600) % 60);

    this.clearTimeIntervalVar = setInterval(() => {
      sec--;
      if (sec === 0) {
        if (min !== 0) {
          min--;
        }
        sec = 60;
        if (min === 0) {
          hr--;
          min = 59;
        }
      }
      return (
        ("00" + hr).slice(-2) +
        " : " +
        ("00" + min).slice(-2) +
        " : " +
        ("00" + sec).slice(-2)
      );
    }, 1000);
  }

.html:

<div class="flex">
    <div class="width-50">Games</div>
    <div class="width-50">Time Left</div>
</div>
<div class="flex" *ngFor="let item of data">
    <div class="width-50">{{ item.game }}</div>
    <div class="width-50">{{ countdownTime(item.timeLeft) }}</div>
</div>

Here's the stackblitz link.

Thanks in advance.

Upvotes: 1

Views: 357

Answers (2)

bossno
bossno

Reputation: 685

Angular Pipes are your friends !

@Pipe({ name: "countdown" })
export class CountdownPipe implements PipeTransform {
  transform(time: number) {
    return interval(1000).pipe(map(i => (time - i) * 1000));
  }
}
<div class="width-50">{{ item.timeLeft | countdown | async | date: "HH:mm:ss": "GMT" }}</div>

https://stackblitz.com/edit/angular-ivy-uiluwk?file=src%2Fapp%2Fapp.component.html

My idea is first of all create an "observable pipe" which decrease your "time" value from seconds to ms. Then piping it with "async" making it readable by the template and then piping again to Date with autoformatting on GMT time.

I didn't implemented what happens when the countdown is done but you can do it in many ways with a condition in the observable with "until" operator or in your template with a ternary.

Observables are very powerfull and well implemented with Angular. https://www.learnrxjs.io/ can be very helpfull to master RxJs.

Ask me for any further questions

Upvotes: 0

Jeremy Thille
Jeremy Thille

Reputation: 26370

In your view, simply display {{ item.timeLeft }}, or {{ secondsToTime(item.timeLeft) }}, a utility that converts seconds to HH:mm:ss. In your component, write an interval that updates every item.timeleft every second.

HTML :

<div class="flex" * ngFor="let item of data" >
    <div class="width-50" > {{ item.game }}</div>
    <div class="width-50" > {{ secondsToTime(item.timeLeft) }}</div>
</div>

TS:

data = [
    {game: "A vs B",timeLeft: 123456},
    {game: "C vs D",timeLeft: 342514},
    {game: "A vs C",timeLeft: 654789},
    {game: "B vs D",timeLeft: 978456}
];
clearTimeIntervalVar: any;

launchInterval(){
    setInterval(() => {
        for (let item of data) item.timeLeft--;
    , 1000})
}


secondsToTime(seconds: number) : string{
    let convertedTime;
    // Here convert secons to HH:mm:ss
    return convertedTime
}

Upvotes: 1

Related Questions