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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With