2
votes

I have a Angular Material table with checkbox on first column. I only want to show the checkbox when the mouse is over the table row.

https://stackblitz.com/angular/pabvkrmvbab?file=app%2Ftable-selection-example.css

I can use css to change the row color on hover, but not sure how to use similar solution to show the checkbox

.mat-row:hover {
    background-color: red;
}
4

4 Answers

6
votes

Easily done with CSS.

.mat-row:hover {
  background-color: red;
}
.mat-row mat-checkbox {
  display: none;
}
.mat-row:hover mat-checkbox {
 display: block;
}
5
votes

You can do it as follows.

Add new boolean property called show to ELEMENT_DATA.

  addShowCheckboxProperty() {
    ELEMENT_DATA.map((data: any) => {
      data.show = false
    });
  }

Use opacity property on mat-checkbox to show/hide checkboxes as follows.

<td mat-cell *matCellDef="let row">
  <mat-checkbox [style.opacity]="row.show || selection.isSelected(row) ? 100 : 0"
                (click)="$event.stopPropagation()"
                (change)="$event ? selection.toggle(row) : null"
                [checked]="selection.isSelected(row)"
                [aria-label]="checkboxLabel(row)">
  </mat-checkbox>
</td>

Handle mouseover and mouseleave events on tr as follows.

HTML

  <tr mat-row *matRowDef="let row; columns: displayedColumns;"
      (click)="selection.toggle(row)" 
      (mouseover)="handleMouseOver(row)" 
      (mouseleave)="handleMouseLeave(row)">
  </tr>

TS

  handleMouseOver(row) {
    const position = row.position;
    ELEMENT_DATA.map((data: any) => {
      if (data.position === position) {
        data.show = true;
      }
    });
  }

  handleMouseLeave(row) {
    const position = row.position;
    ELEMENT_DATA.map((data: any) => {
      if (data.position === position) {
        data.show = false;
      }
    });
  }

As you show your checkbox on mouseover I think no need of select all checkbox on table header row. Find Working StackBlitz.

0
votes

You can use ngIf to check a variable and with mouseenter you can set the same variable to true, to be able to hide just set the same variable to false with mouseleave.

A things like that:

HTML

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" (mouseenter)="isHover=true" 
(mouseleave)="isHover=false">

  <!-- Checkbox Column -->
  <ng-container matColumnDef="select">
    <th mat-header-cell *matHeaderCellDef>
      <mat-checkbox *ngIf="isHover" (change)="$event ? masterToggle() : null"
                    [checked]="selection.hasValue() && isAllSelected()"
                    [indeterminate]="selection.hasValue() && !isAllSelected()"
                    [aria-label]="checkboxLabel()">
      </mat-checkbox>
    </th>
    <td mat-cell *matCellDef="let row">
      <mat-checkbox *ngIf="isHover" (click)="$event.stopPropagation()"
                    (change)="$event ? selection.toggle(row) : null"
                    [checked]="selection.isSelected(row)"
                    [aria-label]="checkboxLabel(row)">
      </mat-checkbox>
    </td>
  </ng-container>

... 

</table>

Componet

isHover: boolean = false;

In this case the checkboxes are popping, but you can add css with transition to have a smooth effect or whetever you need.

0
votes

I would like to add a slightly different take on Sudarshana Dayananda's answer so you don't have to add new fields to your data:

1) Ensure that your data object (for each row) has an "id" field.

2) Add the following to the mat-row:

<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="onRowClicked(row)"
            (mouseover)='mouseOverRow(row)' (mouseleave)='mouseLeaveRow(row)'></tr>

3) And then in .ts set the currently hovered row as a class variable:

mouseOverRow(row) {
this.hoveredRow = row;}

mouseLeaveRow(row) {
this.hoveredRow = null;}

4) So on the checkbox/button you can add:

[class.buttonInvisible]='!hoveredRow || (element.id !== hoveredRow.id)'

My component looks like this:

    <ng-container matColumnDef="select">
                <th mat-header-cell *matHeaderCellDef>
                    <!-- {{ 'Generic.select' | translate }} -->
                </th>
                <td mat-cell *matCellDef="let element" style='text-align:end; width:40px;'>
                    <button [class.buttonInvisible]='!hoveredRow || (element.id !== hoveredRow.id)' class='tableActionButton' mat-icon-button
                        color="accent" aria-label="Delete" (click)="onDeleteClicked(element);$event.stopPropagation();">
                        <mat-icon>delete</mat-icon>
                    </button>
                </td>
            </ng-container>

where buttonInvisible css:

.buttonInvisible{
opacity: 0 !important;}

Let me quickly explain the logic here. The buttonInvisible class is conditionally applied to all checkboxes/buttons when (1) the class hoverRow is not initialised (so no hovering has happened yet) or (2) the row element id does not match the current hovered row's id. So you'll only see the checkbox over the specific row if the id matches the currently hovered set row.