1
votes

I'm trying to create a countdown timer for a daily recurring event in Angular 4 using Rxjs Observable and Async Pipe. Here is my component:

interface Time {
  hours: number;
  minutes: number;
  seconds: number;
}
@Component({
  selector: 'app-header-area',
  templateUrl: './header-area.component.html',
  styleUrls: [ './header-area.component.scss' ]
})
export class HeaderAreaComponent {
  @Input() language: LanguageState;
  @Input() menu: MenuState;

  remaining: Time;
  hoursLeft: number;
  minutesLeft: number;
  secondsLeft: number;

  timeLeft(date) {
    // UTC times
    const utc_hours = date.getUTCHours();
    const utc_minutes = date.getUTCMinutes();
    const utc_seconds = date.getUTCSeconds();
    // End hour
    const end_hour = 20;
    // Difference in hours, minutes, seconds
    const difference_hours = (utc_hours <= end_hour) ? (end_hour - utc_hours) : (24 + end_hour) - utc_hours;
    const difference_minutes = 60 - (utc_minutes % 60) - 1;;
    const difference_seconds = 60 - (utc_seconds % 60) - 1;;
    return <Time>{
      hours: difference_hours,
      minutes: difference_minutes,
      seconds: difference_seconds,   
    }
  }

  constructor() {
    timer(0, 1000).subscribe(() => {
      const time = this.timeLeft(new Date());
      const { hours, minutes, seconds } = time;
      this.hoursLeft = hours;
      this.minutesLeft = minutes;
      this.secondsLeft = seconds;
    });

  }

}

Here is my templte:

<span class="auctions-text">Auctions close in <b>{{ hoursLeft }} hours {{ minutesLeft }}m {{ secondsLeft }}s</b></span>

So, my question is, how would I utilize RXJS timer and other operators to return an Observable, so that I can use it with an async pipe in my template?

1

1 Answers

1
votes

Doing a simple version based on seconds,

const endHours = 20
const endSeconds = endHours * 60 * 60;
const countdown$ = Observable.timer(0, 1000)
  .map(x => endSeconds - x)
  .takeWhile(x => x > 0);

const hoursLeft$ = countdown$.map(x => calcHoursFromSecondsRemaining(x));
const minsLeft$ = countdown$.map(x => calcMinsFromSecondsRemaining(x));
const secsLeft$ = countdown$.map(x => calcSecondsFromSecondsRemaining(x));

<span>{{ hoursLeft$ | async }}</span>
<span>{{ minsLeft$ | async }}</span>
<span>{{ secsLeft$ | async }}</span>