Home > Net >  Countdown timer in Angular pipe not working using pipe and map
Countdown timer in Angular pipe not working using pipe and map

Time:10-06

I'm a little new to RXJS so not really sure how the Pipe and Map are being used here, but the line below never gets called. It's inside a pipe and map.

return this.msToTime(this.getMsDiff(futureDate));

On the screen, I just see [object, object], instead of the countdown timer.

Here is the git repo for this Angular pipe.

I've created a Stacklitz here that shows no output on the screen. If you uncomment out the pipe map section you will see nothing but [object, object] on the screen.

EDIT - If I replace the pipe and map with a subscribe like below I can see the incremental values in console.log, but nothing shows on the screen.

const source = timer(0, 1000);
const abc = source.subscribe(val => {
  const timeRemaining = this.msToTime(this.getMsDiff(futureDate));
  console.log(timeRemaining);
  return timeRemaining;
});

<span class="float-right yb-color">{{event.datePendingUtc | timeRemaining}}</span>

/**
 * @param futureDate    should be in a valid Date Time format
 *                      e.g. YYYY-MM-DDTHH:mm:ss.msz
 *                      e.g. 2021-10-06T17:27:10.740z
 */
public transform(futureDate: string): Observable < string > {
  /**
   * Initial check to see if time remaining is in the future
   * If not, don't bother creating an observable
   */
  if (!futureDate || this.getMsDiff(futureDate) < 0) {
    return null;
  }
  return timer(0, 1000).pipe(
    map(() => {
      // never gets hit
      return this.msToTime(this.getMsDiff(futureDate));
    })
  );
}

/**
 * Gets the millisecond difference between a future date and now
 * @private
 * @param   futureDate: string
 * @returns number  milliseconds remaining
 */
private getMsDiff = (futureDate: string): number => ( (new Date(futureDate)) - Date.now());

/**
 * Converts milliseconds to the
 *
 * @private
 * @param msRemaining
 * @returns null    when no time is remaining
 *          string  in the format `HH:mm:ss`
 */
private msToTime(msRemaining: number): string | null {
  if (msRemaining < 0) {
    console.info('No Time Remaining:', msRemaining);
    return null;
  }

  let seconds: string | number = Math.floor((msRemaining / 1000) % 60),
    minutes: string | number = Math.floor((msRemaining / (1000 * 60)) % 60),
    hours: string | number = Math.floor((msRemaining / (1000 * 60 * 60)) % 24);

  /**
   * Add the relevant `0` prefix if any of the numbers are less than 10
   * i.e. 5 -> 05
   */
  seconds = (seconds < 10) ? '0'   seconds : seconds;
  minutes = (minutes < 10) ? '0'   minutes : minutes;
  hours = (hours < 10) ? '0'   hours : hours;

  return `${hours}:${minutes}:${seconds}`;
}

CodePudding user response:

Move msToTime function inside rxjs map

return source.pipe(
  map(_ => this.msToTime(this.getMsDiff(futureDate)))
);

In template you see [object, object] because you are returning Observable from filter pipe, so use Async to subscribe it like

<div> date countdown: {{ '2021-10-06T17:27:10.740z' | filter | async }} </div>

Demo

  • Related