0

I am using a mat-slide-toggle inside mat-table. Each row has a column containing mat-slide-toggle and another column containing a button. I want to pass mat-slide-toggle's value to button's click function as an argument.

<ng-container matColumnDef="show waiting list">
  <mat-header-cell *matHeaderCellDef> Show Waiting List</mat-header-cell>
  <mat-cell *matCellDef="let element">
    <mat-slide-toggle></mat-slide-toggle>
  </mat-cell>
</ng-container>

<ng-container matColumnDef="play">
  <mat-header-cell *matHeaderCellDef> Play</mat-header-cell>
    <mat-cell *matCellDef="let element">
      <button (click)="play(element, toggleValueGoesHere)" mat-icon-button>
        <mat-icon class="mat-18">play_arrow</mat-icon>
      </button>
    </mat-cell>
</ng-container>

How would this be achieved using formControl? If not is there another way?

Awais Saeed
  • 55
  • 1
  • 12
  • I haven't used Angular in a while, but in React you would hoist the state of the toggle button to the closest common parent component. That parent component would pass down a function to change the state to the toggle button, and pass the actual state value to the button. Toggling would change the state in the parent component, updating both children components. – Marcus Cemes Feb 23 '20 at 16:07
  • The common parent of these two element is mat-table which also contains all rows. Updating state from there would change state of all rows. – Awais Saeed Feb 23 '20 at 16:11
  • mat-table is the closest "component" in the tree, but what I meant is your closest Angular component, which can actually hold custom state. If I remember correctly, an angular component is split made from a .html file and a .ts file? Make a state variable in the .ts script, and pass it to both the toggle and the button. The toggle can change the state, the button will read from it (two-way binding), and Angular should optimise to only update those two specific components, or if not, the render should be negligible anyway. – Marcus Cemes Feb 23 '20 at 16:21

2 Answers2

1

You can easily achieve this with the help of *matCellDef. Instead of assigning it to element, you can assign it to row. Please find the complete code in below stackblitz:

URL - https://stackblitz.com/edit/angular-emnxjb

In our case we will use this property with button ng-container and will pass the entire row. And with this we will have data of mat-slide-toggle as well. I am alerting those values for demo.

I am just solving issue of how to pass value from one column to another, I hope you will handle rest.

Please let me know if any questions.

UPDATED CODE FOR WORKAROUND

In this approach i am keeping a track of mat slide toggle which are active in array called slideTrueArray. When user clicks a button, it send the row index and based on the fact if that index if present in array, I am consoling the output.

import {SelectionModel} from '@angular/cdk/collections';
import {Component} from '@angular/core';
import {MatTableDataSource} from '@angular/material/table';

export interface Playlist {
  id: number;
    name: string;
}

const ELEMENT_DATA: Playlist[] = [
  {id: 1, name: 'first'},
  {id: 2, name: 'second'},
  {id: 3, name: 'third'},
];

/**
 * @title Table with selection
 */
@Component({
  selector: 'table-selection-example',
  styleUrls: ['table-selection-example.css'],
  templateUrl: 'table-selection-example.html',
})
export class TableSelectionExample {
  canShowWaitingList: any;
  displayedColumns: string[] = [ 'show waiting list', 'play'];
  dataSource = new MatTableDataSource<Playlist>(ELEMENT_DATA);
  slideTrueArray: number[] = [];

  constructor() {
  }

  play(i: any) {
    const isExist = this.slideTrueArray.indexOf(i);
    const slideValue = isExist !== -1 ? true : false;
    alert(slideValue);
  }

  toggleCurrentSlide(index:number) {
    debugger;
    const isSlideExist = this.slideTrueArray.indexOf(index);
    if(isSlideExist !== -1) {
      this.slideTrueArray.splice(isSlideExist, 1);
    } else {
      this.slideTrueArray.push(index);
    }
  }

}

table-selection-example.html

<mat-table [dataSource]="dataSource" matSort>
    <ng-container matColumnDef="show waiting list">
        <mat-header-cell *matHeaderCellDef> Show Waiting List</mat-header-cell>
        <mat-cell *matCellDef="let element; let i = index;">
            <mat-slide-toggle (change)="toggleCurrentSlide(i)"></mat-slide-toggle>
        </mat-cell>
    </ng-container>

    <ng-container matColumnDef="play">
        <mat-header-cell *matHeaderCellDef> Play</mat-header-cell>
        <mat-cell *matCellDef="let element; let i = index;">
            <button (click)="play(i)" mat-icon-button>
        <mat-icon class="mat-18">play_arrow</mat-icon>
      </button>
        </mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns; sticky:true"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
Akash Bhardwaj
  • 346
  • 1
  • 3
  • 9
Jasdeep Singh
  • 7,901
  • 1
  • 11
  • 28
  • I am using **let row** but it still returns element. ` Play ` – Awais Saeed Feb 23 '20 at 17:13
  • can you please create a stackblitz like i have created, it would be easier to check your code. Because you can check my code both template and ts file, its working – Jasdeep Singh Feb 23 '20 at 17:18
  • I don't want to create a variable to store mat-slide-toggle value because I would not need it later. It will reset to checked after reload. I will use it only once, when play button is clicked. – Awais Saeed Feb 23 '20 at 17:42
  • Hi Buddy, I think this is the most ideal way where we have a data to keep track of a columns. If you need a workaround then still we need to maintain an array about which mat-slides are true and which are not. I am updating the code here, you can copy paste in your stackblitz and check. – Jasdeep Singh Feb 24 '20 at 03:07
0

I found something similar on this thread. Thought it might help you.

Pass checkbox value to angular's ng-click

Apurva Pathak
  • 692
  • 1
  • 9
  • 22