Angular - Activate button only on the specific row where it was clicked

I'm facing an issue with a table that contains buttons in one of the columns. Whenever I click on a button, all buttons in the column get enabled instead of just the clicked one. Can someone help me find a solution to this problem?

I've attempted passing the line number as a parameter but haven't been successful so far.

HTML

 <div *dxTemplate="let data of 'cellTemplate'">
  <button type="button" data-toggle="dropdown" class="btn ClassPlay">
    <img src="./assets/play.svg" *ngIf="currentState=='pause'">
    <img src="./assets/playV.svg" *ngIf="currentState=='start'">
  </button>
  <div class="dropdown-menu">
    <a class="dropdown-item" *ngIf="currentState=='pause'" routerLinkActive="active"
      (click)="currentState='start'; startTimer(data, data.rowIndex)">Start</a>
    <a class="dropdown-item" *ngIf="currentState=='start'" routerLinkActive="active"
      (click)="currentState='pause'; pauseTimer((data, data.rowIndex)">Pause</a>
  </div>
  <span class="timer">{{display}}</span>
</div>

Component.ts

startTimer(data,row) {
  this.interval = setInterval(() => {
    if (this.time === 0) {
      this.time++;
    } else {
      this.time++;
    }
    this.display=this.transform( this.time)
  }, 1000);
}

     transform(value: number): string {
   var sec_num = value; 
 var hours   = Math.floor(sec_num / 3600);
 var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
 var seconds = sec_num - (hours * 3600) - (minutes * 60);

 return hours+':'+minutes+':'+seconds;
 }

 pauseTimer(data,row) {
  clearInterval(this.interval);
}

What I Tried

<button type="button" data-toggle="dropdown" class="btn ClassPlay">
    <img src="./assets/play.svg" *ngIf="currentState=='pause'">
    <img src="./assets/playV.svg" *ngIf="currentState=='start' && currentRowIndex === data.rowIndex">
  </button>
  <div class="dropdown-menu">
    <a class="dropdown-item" *ngIf="currentState=='pause'" routerLinkActive="active"
      (click)="currentState='start'; startTimer(data)">Start</a>
    <a class="dropdown-item" *ngIf="currentState=='start' && currentRowIndex === data.rowIndex" routerLinkActive="active"
      (click)="currentState='pause'; pauseTimer(data)">Pause</a>
  </div>
  <span class="timer">{{currentRowIndex === data.rowIndex ? display : ''}}</span>

startTimer(data) {
  this.currentRowIndex = data.rowIndex;
  this.interval = setInterval(() => {
    if (this.time === 0) {
      this.time++;
    } else {
      this.time++;
    }
    this.display=this.transform( this.time)
  }, 1000);
}

   transform(value: number): string {
 var sec_num = value; 
var hours   = Math.floor(sec_num / 3600);
var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
var seconds = sec_num - (hours * 3600) - (minutes * 60);

return hours+':'+minutes+':'+seconds;
}

pauseTimer(data) {
  this.currentRowIndex = data.rowIndex;
  clearInterval(this.interval);
}

The challenge now is when I click the start button, all buttons on other lines disappear momentarily and only reappear on the next line. The timer also behaves incorrectly, accumulating time across lines rather than starting anew on each click.

Answer №1

After reviewing your inquiry, it seems like the solution provided below may be helpful:

<div *dxTemplate="let data of 'cellTemplate'">
      <button type="button" data-toggle="dropdown" class="btn ClassPlay">
        <img src="./assets/play.svg" *ngIf="currentState=='pause'">
        <img src="./assets/playV.svg" *ngIf="currentState=='start' && currentRowIndex === data.rowIndex">
      </button>
      <div class="dropdown-menu">
        <a class="dropdown-item" *ngIf="currentState=='pause'" routerLinkActive="active"
          (click)="currentState='start'; startTimer(data, data.rowIndex)">Start</a>
        <a class="dropdown-item" *ngIf="currentState=='start' && currentRowIndex === data.rowIndex"routerLinkActive="active"
          (click)="currentState='pause'; pauseTimer()">Pause</a>
      </div>
      <span class="timer">{{currentRowIndex === data.rowIndex ? display : '00'}}</span>
    </div>

In your .ts file:

currentRowIndex = null; // Define this in your component

startTimer(index) {
    this.currentRowIndex = index;
    this.interval = setInterval(() => {
      if (this.time === 0) {
        this.time++;
      } else {
        this.time++;
      }
      this.display=this.transform( this.time)
    }, 1000);
  }

transform(value: number): string {
      var sec_num = value; 
    var hours   = Math.floor(sec_num / 3600);
    var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
    var seconds = sec_num - (hours * 3600) - (minutes * 60);

    return hours+':'+minutes+':'+seconds;
}

pauseTimer() {
    this.currentRowIndex = null;
    clearInterval(this.interval);
}

Answer №2

After analyzing your code, it seems like you are consistently updating the variable currentState. When the Start button (anchor) is clicked for the first time, such as in this instance:

(click)="currentState='start'; ....//

You are assigning the value 'start' to the shared variable currentState. Consequently, all instances of ngIf react to this change. I believe what you intend to achieve is having a boolean value that indicates the current state for each row in the table.

Update: Here is an example illustrating what I think you are aiming for:

<div class="dropdown-menu">
        <a class="dropdown-item" *ngIf="currentState=='pause'" routerLinkActive="active"
          (click)="startTimer(data.rowIndex)">Start</a>
        <a class="dropdown-item" *ngIf="currentState=='start'" routerLinkActive="active"
          (click)="pauseTimer()">Pause</a>
      </div>

Additionally, here is what your Component.ts should look like:

  public dataArray: Array<DataItem>;
  public timeArray: Array<number>;
  public interval;

  constructor() {
    this.dataArray = // initialize your data here

    // Create an array to store the time for each element and initially fill it with zeroes
    this.timeArray = new Array(this.dataArray.length).fill(0);
  }

  // It's important to know the index to determine which timer to increment
  startTimer(rowIndex) {
    this.interval = setInterval(() => {
      this.timeArray[rowIndex]++;
      // Display the current ongoing timer
      this.display=this.transform(this.timeArray[rowIndex])
    }, 1000); 
  }

  pauseTimer(rowIndex) {
    // alert(this.timeArray[rowIndex]) <-- used for test only
    clearInterval(this.interval); // Stop the interval
  }

Update 2 Considering your latest requirements, you also want to display the timer for each row. Here's how you can accomplish that:

<span class="timer">{{transform(timeArray[rowIndex])}}</span>

In this implementation, we utilize the transform function on the value corresponding to the rowIndex.

Update 3 To address the issue from your previous update, follow this solution:

.. *ngIf="currentState=='start' && currentRowIndex === data.rowIndex" 

The use of && ensures the condition applies only to the current row, displaying it exclusively. By removing the operator like so:

.. *ngIf="currentState=='start'" 

To reset the timer for a row when pausing, add the following line within the pauseTimer function:

this.timeArray[rowIndex] = 0; // Reset the timer for the specific row

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

Is there a way to efficiently load the json files only upon clicking the corresponding language button?

Currently, I am using a tutorial on implementing translations in Angular2. The implementation works well, but I would like to optimize it by loading json files only when the associated language button is clicked. Can someone assist me with this? // app/tr ...

Steps for sending a model and a collection of files to a .NET MVC controller from an Angular version 4 or above application

I'm facing an issue while sending a model and attachments from an Angular 4.2.4 to a .Net 4.6 (MVC 4.0) Controller. Here are the sample models: //JS model { ID: number; Name: string NewAttachments: any } //.Net model { int ID {get;set;} string ...

Change array association with object extension

I am looking to transform the assignment below into one that utilizes object spread: bData.steps[bStepKey].params= cData[cKey] My attempt so far has been unsuccessful. bData= {...bData, steps:{ ...bData.steps[bStepKey], params: cData[cKey]}} ...

What is the process for converting a .ts file to a .js file within a Next.js project for Web worker implementation?

I am currently working on a TypeScript Next.js project: "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint& ...

A TypeScript function with nested options and a variable rest parameter: The type 'T' is open to instantiation with various subtypes

Let's consider the following simplified example that showcases my issue: const customFactory = <T extends unknown[]>( customFn: (...args: T) => void ) => { const modifiedCustomFn = (...args: T) => { console.log('Called with ...

What could be causing the tap operator to fail to fire in this scenario?

I'm struggling to understand why the rxjs tap() operator is not firing in my Angular component, even though the Subject value is being updated on the screen. I've also experimented with using a BehaviorSubject instead, but encountered the same is ...

How can I display or hide an ion-icon in the ion navbar based on internet connectivity status?

Can anyone help me with showing or hiding ion-icons based on internet connectivity status? I am a bit confused about this, so any assistance would be appreciated. Thank you. I have implemented the following in HTML using ngIf function: <ion-buttons end ...

Placing images inside a div causes them to vanish

I encountered a strange issue where the images I added to a background disappeared. .Background1{ position:relative; top:0%; left:0%; height:100%; width:100%; content:url("/assets/backgroundlayer1.jpg") } .Background2{ posi ...

Switching from the HTTPS to HTTP scheme in Angular 2 HTTP Service

I encountered the following issue: While using my Angular service to retrieve data from a PHP script, the browser or Angular itself switches from HTTPS to HTTP. Since my site is loaded over HTTPS with HSTS, the AJAX request gets blocked as mixed content. ...

Retrieving the value of a variable within an object using an Observable

Can someone help me figure out how to assign a variable to a value inside an object in an Observable in my typescript file? I can retrieve the variable's value in my HTML file, but I seem to be missing something crucial. I believe the solution may inv ...

Creating TypeScript versions of `delegate` pattern JavaScript code

Looking for a way to convert the following javascript code into typescript? const handlers = { say (msg) { console.log(msg) }, add (a, b) { return a + b } } function caller (method, ...args) { if (handlers[method]) return handlers[methd ...

Angular `build` is encountering an error when dealing with externals that are declared using `webpack`

When working with Angular, I successfully load jquery from an external source. However, after the build process, I encounter a troubling error message: Uncaught ReferenceError: jQuery is not defined. It's worth noting that my build does download the j ...

Encountered an issue when attempting to post to an ASP.NET Core Web API utilizing Windows authentication

The setup consists of an AspNetCore WebApi using default configuration for Windows authentication and CORS enabled. The client side utilizes Angular with both GET and POST methods implemented. Successfully executing the GET call: this.http.get("https://l ...

Creating Personalized Validators for Angular Version 5 Reactive Forms

I am struggling to create a custom validator for my Angular v5 application. I followed the documentation for a basic password match example in the Docs, but it's not working as expected. this.personalInfoForm = _fb.group({ 'name': [null,V ...

Making a request in Angular to delete data in Express

I am developing an endpoint to handle the deletion of items from a database. Users will be able to select the item they want to delete by checking a checkbox in a table. On the frontend, I am using Angular, while on the backend I'm utilizing Mongoose ...

Is it possible to programmatically alter dropdown values in an Ionic 2 TypeScript file?

One form has been created with dependent drop-downs and some input fields. I am aiming for it to work in two scenarios: If the session is initially null, then no data should be displayed in the form and all fields should be blank by default (which has al ...

Need help updating your Angular2 project to Angular6? Encounter an issue like this: "AppModule" declaring an unexpected module 'HttpClientModule'? Let us assist you with our expert rewriting services

I recently updated a service that was functioning flawlessly in Angular 2, and attempted to rewrite it using Angular 6. Below is the code for the service: import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from &apos ...

Unable to include option object in the SHA3 function using typescript

The SHA3 function allows for customizing the output length, as demonstrated in the code snippet below: var hash = CryptoJS.SHA3("Message", { outputLength: 512 }); var hash = CryptoJS.SHA3("Message", { outputLength: 384 }); var hash = CryptoJS.SHA3("Messag ...

Having an issue where Firebase Firestore is showing [object, object] instead of the expected document data. What steps should be

I have developed an application that collects user input and uploads it to firebase firestore. However, when I retrieve the documents from firestore to display on another page using a component, it shows [object, object] instead of the actual data. I am ...

Filtering dates using the Angular Material Date filter on a single adapter

After implementing a custom date format for my mat-datepicker, I encountered a specific challenge: export const PICK_FORMATS = { parse: {dateInput: {month: 'short', year: 'numeric', day: 'numeric'}}, display: { date ...