Reputation: 121
I am trying to display a timer as shown below in this screenshot. To count up constantly to show how long since this entry has been made.
I couldn't find too many options for doing it in Angular. I found this solution in Angular JS. https://siddii.github.io/angular-timer/ I need the timer exactly like this. But I was not able to port it into Angular or I couldn't. So tried the other alternatives available and found these still they are all also not working.
https://www.npmjs.com/package/ng2-simple-timer
https://www.npmjs.com/package/ngx-timer
The closest I got to was this ngx-timer's Countup-timer. https://www.npmjs.com/package/ngx-timer the timer works fine and its able to start from a given date as per my requirement. startTimer(startDate). But it has an known issue which is still unresolved that is it applies itself to the last known index of the timer element thereby only one timer running in a whole list of timers.You can notice that in the above given screenshot itself.
its a known bug. https://github.com/Y4SHVINE/ngx-timer-lib/issues
So can somebody help me with a solution or some tweaks to one of these solutions to make it work.
Thanks.
Upvotes: 1
Views: 16396
Reputation: 13515
I would do this by writing a function to return the difference between the current time and the creation time of an object.
My initial thought was to return the difference as a Date
object and then format the result. I soon ran into problems when formatting different time spans, as a date is not the same thing as a time span.
So instead of trying to format a Date
that is pretending to be a time span, I would create my own interface.
export interface TimeSpan {
hours: number;
minutes: number;
seconds: number;
}
By doing this we retain control of how time spans >= 1 day are handled, and avoid time zone issues.
I would use OnPush
change detection to keep control over when change detection is run:
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
constructor(private changeDetector: ChangeDetectorRef) {}
}
I would then kick off an RxJS interval
in ngOnInit()
, making sure to unsubscribe when we're finished:
private destroyed$ = new Subject();
ngOnInit() {
interval(1000).subscribe(() => {
this.changeDetector.detectChanges();
});
}
ngOnDestroy() {
this.destroyed$.next();
this.destroyed$.complete();
}
The HTML would then get the elapsed time from a function on my component:
getElapsedTime(entry: Entry): TimeSpan {
let totalSeconds = Math.floor((new Date().getTime() - entry.created.getTime()) / 1000);
let hours = 0;
let minutes = 0;
let seconds = 0;
if (totalSeconds >= 3600) {
hours = Math.floor(totalSeconds / 3600);
totalSeconds -= 3600 * hours;
}
if (totalSeconds >= 60) {
minutes = Math.floor(totalSeconds / 60);
totalSeconds -= 60 * minutes;
}
seconds = totalSeconds;
return {
hours: hours,
minutes: minutes,
seconds: seconds
};
}
This function starts off by getting the total number of seconds elapsed since the creation date, and then works out the hour, minute, and second components.
Where entry
is the object that contains some Date
instance indicating its creation time. For my demo, I am using this interface:
export interface Entry {
created: Date;
id: string;
}
The elapsed time span can then be retrieved for each instance inside an *ngFor
like this:
<span *ngIf="getElapsedTime(entry) as elapsed">
{{elapsed.hours}} h {{elapsed.minutes}} m {{elapsed.seconds}} s
</span>
DEMO: https://stackblitz.com/edit/angular-p1b9af
Upvotes: 6
Reputation: 2890
You could do this with RxJS like this:
const startDate = new Date('2020-03-08 14:12:23');
timer(1000, 1000)
.pipe(
map((x: number) => {
const newDate = new Date(startDate.getTime());
newDate.setSeconds(newDate.getSeconds() + x);
return newDate;
})
)
.subscribe(t => this.myDate = t);
Then in your component you do:
<div>{{ mydate | date: "hh 'h' mm 'm' ss 's'" }}</div>
Upvotes: 2