Harry
Harry

Reputation: 621

Angular - Enable button only on line where clicked

I have a table with some details. My problem is that in one of the columns I have buttons. For example, I click the button on line 0 but all buttons are enabled. Does anyone know how I can solve this?

Already tried to pass the line number, but so far unsuccessful :(

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 only problem now is that when I click the start button all buttons on the other lines disappear and only reappear on the next line. Time is also wrong, I start the timeline on one line and when I start on the other, the time always keeps adding up and not starting over as it should

Upvotes: 5

Views: 472

Answers (2)

Lykos94
Lykos94

Reputation: 593

Based on your code, my assumption is that you are always changing the same variable currentState. Once you click the Start button (anchor) the first time like here

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

you are setting the shared variable currentState to the start value. Therefore all the ngIf react to it. What you I believe you want to achieve is having something like a boolean value that express the current state for each row in the table.

Update: Here is an example of what I think you want to achieve

 <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>

And this should be your Component.ts

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

  constructor() {
    this.dataArray = // constructor of your data

    // We create an array to keep track of the time for each element
    // and fill the array initially with zeroes
    this.timeArray = new Array(this.dataArray.length).fill(0);
  }

  // We need here to know the index in order to know what timer to increment in the array
  startTimer(rowIndex) {
    this.interval = setInterval(() => {
      this.timeArray[rowIndex]++;
      // The display will always show the current ongoing timer
      this.display=this.transform(this.timeArray[rowIndex])
    }, 1000); 
  }

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

Update 2 From your last update, i believe you want also to show the display for each row. Here how to achieve it

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

as you can see I don't use the display variable, but apply your transform function to the value of the rowIndex

Update 3 The solution to the last problem you posted is the following

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

the && is returning true only for the current row, therefore only that one is displayed. Remove it like this

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

and to reset the timer for the row when you press pause

pauseTimer(rowIndex) {
    this.timeArray[rowIndex] = 0; // Add this line
    clearInterval(this.interval); // Clears the interval
  }

Upvotes: 1

Ashot Aleqsanyan
Ashot Aleqsanyan

Reputation: 4453

If I understand correctly your question, I can offer this solution.

<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>

and in .ts

currentRowIndex = null; // you need to define 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);
  }

Upvotes: 1

Related Questions