Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically update display of relative time with Moment.js

Given a list of items (think of it as a chat with multiple messages), I'd like to use moment.js to display the relative time (e.g. since creation) for each item.

Each item has its own component and relative time is displayed using the following code:

get timeFromNow(): string {
  return moment(this.pageLoaded).fromNow(); // pageLoaded is a JS Date
}

The issue is that the component won't update the display of relative time, since the original input (pageLoaded in the example above) won't change.

My question is: is there a best practice for dealing with such a scenario? Currently, I'm using markForCheck of ChangeDetectorRef to trigger re-rendering. However, I'm not sure if this is a good method performance-wise.

I've created a simple demo on Stackblitz. In the demo, I use the aforementioned markForCheck to trigger the update.

like image 594
tilo Avatar asked Dec 13 '22 15:12

tilo


1 Answers

From a technical point of view you have a good solution. If you want a better design then enter the world of reactive programming.

Instead of starting a check manually you can use a stream and let Angular do the work:

export class MomentComponent implements OnInit  {
  pageLoaded: Moment;
  timeFromNow: Observable<string>;

  ngOnInit() {
    this.pageLoaded = moment(new Date());

    this.timeFromNow = interval(1000).pipe(
                         map(() => this.pageLoaded.fromNow()),
                         distinctUntilChanged()
                       );
  }
}

interval works like setInterval in your example: It emits a value every 1000ms. Then we replace this value by a time string. That's it. Every second a new time string is emitted. I added distinctUntilChanged() so that a new value is only emitted when it's different from the old one.

In your template you can consume the stream using the async pipe:

template: `Page loaded: <span class="relativeTime">{{ timeFromNow | async}}</span>`

The HTML will be updated when a new time string is emitted. No unnecessary checks and calculations. As a bonus by using the async pipe the timer is cancelled automatically when the component is destroyed and you don't create a memory leak.

You can check the forked demo.

like image 198
a better oliver Avatar answered Dec 28 '22 09:12

a better oliver