What is the best approach to incorporate a stopwatch?

I'm exploring ways to track the time it takes for a user to click a button. While I have a working solution, I'm curious if there's a more efficient method available. Below is my current implementation:

export class MainComponent implements OnInit {

    timer : number = 0;
    intervalId : number;

    constructor() {
      this.intervalId = setInterval(() => {
        this.timer++;
      }, 1000);
    }

    ngOnInit() {}

    buttonClick = function() {
    alert(this.timer);
    this.timer = 0;
    }
}

Answer №1

Opt for performance.now() to ensure precise time-stamps (or fallback to new Date().getTime()) and calculate the time difference in UI update callbacks using setInterval. Avoid relying on setInterval to track time as it may not execute exactly every 1000ms.

Additionally, I have transferred the timer logic to the ngOnInit method instead of keeping it in the constructor function.

export class MainComponent implements OnInit {

    private start: number = null;
    private uiTimerId: number = null;

    constructor() {
    }

    private updateUI(): void {

        let delta = performance.now() - this.start;
        this.someUIElement.textContent = delta.toFixed() + "ms";
    }

    ngOnInit() {

        this.start = parseFloat( window.localStorage.getItem( "timerStart" ) );
        if( !this.start ) {
            this.start = performance.now();
            window.localStorage.setItem( "timerStart", this.start );
        }

        this.uiTimerId = window.setInterval( this.updateUI.bind(this), 100 ); // Update UI every 100ms for smoother interface
    }

    buttonClick = function() {
        if( this.uiTimerId != null ) {
            window.clearInterval( this.uiTimerId );
            window.localStorage.removeItem( "timerStart" );
        }
    }
}

Answer №2

First and foremost, it's important to note that we define our member functions differently in TypeScript. Therefore, the buttonClick function should be written as follows:

buttonClick() {
  alert(this.timer);
  this.timer = 0;
}

As suggested by @Dai, a more efficient and accurate approach would be to get the system time at initialization (ngOnInit) and calculate the difference from the system time on click.

ngOnInit() {
  this.startTime = localStorage.startTime ? JSON.parse(localStorage.startTime) : (new Date().getTime());
  localStorage.setItem('startTime', JSON.stringify(this.startTime));
}

buttonClick() {
  this.startTime = JSON.parse(localStorage.startTime);
  alert((this.startTime - (new Date().getTime())) / 1000);
}

UPDATE: I have revised the answer to demonstrate how to utilize localStorage for persisting values. While similar to the previous solution, this approach employs idiomatic TypeScript practices. For those accustomed to ES5 methods, there is no issue with using them; however, I find this style to be clearer and easier to understand. To enhance your TypeScript skills, consider going through an Angular tutorial such as the "Tour of Heroes" on the official website. Additionally, using Visual Studio Code with the Angular Essentials plugin can help format and lint your code correctly. This will assist you in familiarizing yourself with idiomatic TypeScript coding. Best of luck!

Answer №3

Here is an alternative way to code a stopwatch without using an increment timer. The timer's increment will adjust when the tab is inactive. I have implemented a stopwatch in a highly efficient manner that allows for seamless switching between tabs without affecting the time count. You can easily reset, pause, and play the stopwatch. For more details, you can refer to the provided link.

  seconds: string = "00";
  minutes: string = "00";
  hours: string = "00";
   timer(){
    let mcountercal = 0;
    let currentSeconds = parseInt(this.seconds);
    let currentMinutes = parseInt(this.minutes);
    let currentHours = parseInt(this.hours);
    this.counter = currentHours * 3600000 + currentMinutes * 60000 + currentSeconds * 1000
    const startTime = Date.now() - (this.counter || 0);
    this.timeoutId = setInterval(() => {
      this.counter = Date.now() - startTime;
      currentHours = Math.floor(this.counter / 3600000);
      currentMinutes = Math.floor(this.counter / 60000) - currentHours * 60;
      mcountercal = Math.floor(this.counter / 60000);
      currentSeconds = Math.floor(this.counter / 1000) - mcountercal * 60;     
      this.hours = this.getFormattedTimeStamp(currentHours.toString());
      this.minutes = this.getFormattedTimeStamp(currentMinutes.toString())
      this.seconds = this.getFormattedTimeStamp(currentSeconds.toString())
}

getFormattedTimeStamp(timestamp:any) {
  return timestamp < 10 ? "0" + timestamp : timestamp;
}

https://stackblitz.com/github/Ashraf111/StopWatchWhenTabActiveAndInactive

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 2 does not include Bootstrap CSS by default

Found this helpful tip at https://angular.io/docs/ts/latest/guide/forms.html Time to include the stylesheet you need. Go to your application's root folder in the terminal and run this command: npm install bootstrap --save In index.html, make sure ...

Steps for converting TypeScript code to JavaScript using jQuery, without the need for extra libraries or frameworks like NPM

My single-page dashboard is quite basic, as it just displays weather updates and subway alerts. I usually refresh it on my local machine, and the structure looked like this: project/ index.html jquery-3.3.1.min.js script.js I decided to switch it t ...

Updating Elements in an Array Using JavaScript is Not Functioning as Expected

In my Angular application, I have included some lines of TypeScript code which involve Boolean variables in the constructor and an array of objects. Each object in this array contains input variables. selftest: boolean; failed: boolean; locoStateItem ...

Sending an onclick event to a child class through React and TypeScript

I'm currently working through the Facebook React tutorial with Typescript for the first time. I need to pass an onClick event to the 'Square' component, which is implemented using Typescript and interfaces for state and props. How can I mod ...

Adding a dynamic click event in HTML using IONIC 4

I've created a function using Regex to detect URL links and replace them with a span tag. The replacement process is working fine, but I'm facing an issue where when I include (click)="myFunction()" in the span, it doesn't recognize the cli ...

Uploading files using Angular 6 to communicate with a Flask (Python) API

I have developed a web service using Flask to save files, following the example provided in the official Flask documentation: @app.route('/parse_table', methods=['POST']) def upload_file(): print(request.files) # check if the p ...

What is the best way to implement an onClick event listener in a TypeScript React application?

Is there a way to properly add an onClick event listener to a div element in my code snippet below? useEffect(() => { if (ref.current === null) { return; } const handleClick = (el: HTMLDivElement, e: MouseEvent) = ...

Improve your code quality with TypeScript's type checking capabilities

I am currently utilizing TypeScript version 1.4.1 and I have a need to import an external module (specifically "chai") while ensuring type checking compatibility. Yet, I seem to be facing a naming conflict issue with the following code snippet: /// <r ...

Error in WebStorm: Troubleshooting HTML file issue in Angular application

I encountered an error in WebStorm while working on a new project where I was testing a form. The issue only arises when I run ng serve, although no errors are reported and the application runs smoothly. To troubleshoot, I tried deleting my node_modules f ...

Sending Angular 4 POST request to Java Spring Controller via HTTP

Hey there, I'm looking to pass a string from my Angular 4 post request to my Java Spring MVC controller and get its value returned. In the Angular 4 function: let body = 'example' http .post('favourite', body) .subscribe( ...

Receiving a null value when accessing process.env[serviceBus]

Currently, I am focusing on the backend side of a project. In my environment, there are multiple service bus URLs that I need to access dynamically. This is how my environment setup looks like: SB1 = 'Endpoint=link1' SB2 = 'Endpoint=link2&a ...

Mastering the art of connecting content within Prismic

I have been working on creating a mega menu for my website header, but I am encountering a type error. Has anyone else faced this issue before and how did you resolve it? I am currently importing the generated types from @/prismicio-types. Here is an exam ...

Is there a way to trigger an image flash by hovering over a button using the mouseover feature in AngularJS2?

When I hover over the 'click me' button, I want an image to appear on the webpage. When I stop hovering, the image should disappear using the mouseover option. This is what I attempted in my app.component.ts and my.component.ts files: Here is t ...

What is the best way to take any constructor type and transform it into a function type that can take the same arguments?

In the code snippet below, a class is created with a constructor that takes an argument of a generic type. This argument determines the type of the parameter received by the second argument. In this case, the first parameter sets the callback function&apos ...

Nest JS is currently experiencing difficulties with extending multiple classes to include columns from other entities

Currently, I am immersed in a new project that requires me to enhance my entity class by integrating common columns from another class called BASEMODEL. import { Index, PrimaryGeneratedColumn } from "typeorm"; export class BaseModel { @Prima ...

Tips for correctly referencing the router link within the mat-sidenav component in Angular 7

As a newcomer to Angular, I am facing an issue where I need to use the same router link in both my mat-list-item and the sub mat-sidenav-content. For instance: [routerLink]="['/list',{outlets: {sidebar: ['general', employee.userId]}}] ...

Add a tooltip to the mat-tab title

I have been attempting to implement tooltips on tabs using matTooltip, but I can't seem to get it working. Despite referencing the documentation and searching through Stack Overflow questions, I am unable to identify the root cause of this issue. Cou ...

Issues with manipulating state using TypeScript Discriminated Unions"Incompatibility with setState

Imagine having a unique type structure like the one shown below: export type IEntity = ({ entity: IReport setEntity: (report: IReport) => void } | { entity: ITest setEntity: (test: ITest) => void }); Both the entity and setEntity fun ...

Is there a tool in Node.js to set up a new project, similar to the scaffolding feature in Visual Studio for C# projects

Is there a way to efficiently create a node.js project with TypeScript and Express, and embed an SPA client using React and Redux templates written in TypeScript as well? Is there a scaffolding tool available to streamline this process, similar to the ea ...

Ways to verify the identity of a user using an external authentication service

One of my microservices deals with user login and registration. Upon making a request to localhost:8080 with the body { "username": "test", "password":"test"}, I receive an authentication token like this: { "tok ...