Angular 4 Material table highlight a row

I'm looking for a good way to highlight the whole a row in md-table.
Should I do directive or what?

<div class="example-container mat-elevation-z8">
  <md-table #table [dataSource]="dataSource">

    <!--- Note that these columns can be defined in any order.
          The actual rendered columns are set as a property on the row definition" -->

    <!-- ID Column -->
    <ng-container cdkColumnDef="userId">
      <md-header-cell *cdkHeaderCellDef> ID </md-header-cell>
      <md-cell *cdkCellDef="let row"> {{row.id}} </md-cell>
    </ng-container>

    <!-- Progress Column -->
    <ng-container cdkColumnDef="progress">
      <md-header-cell *cdkHeaderCellDef> Progress </md-header-cell>
      <md-cell *cdkCellDef="let row"> {{row.progress}}% </md-cell>
    </ng-container>

    <!-- Name Column -->
    <ng-container cdkColumnDef="userName">
      <md-header-cell *cdkHeaderCellDef> Name </md-header-cell>
      <md-cell *cdkCellDef="let row"> {{row.name}} </md-cell>
    </ng-container>

    <!-- Color Column -->
    <ng-container cdkColumnDef="color">
      <md-header-cell *cdkHeaderCellDef>Color</md-header-cell>
      <md-cell *cdkCellDef="let row" [style.color]="row.color"> {{row.color}} </md-cell>
    </ng-container>

    <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
    <md-row *cdkRowDef="let row; columns: displayedColumns;"></md-row>
  </md-table>
</div>

Table from: https://material.angular.io/components/table/overview


Solution 1:

Update for Newer Material Version (md --> mat):

html:

<!-- Add the highlight class in row definiton of md-table -->
<!-- Add click event to pass the selected row index -->

<mat-row *cdkRowDef="let row; columns: displayedColumns;" 
         [ngClass]="{'highlight': selectedRowIndex == row.id}"
         (click)="highlight(row)">
</mat-row>

Original Answer:

You can do it by using ngClass and a flag like selectedRowIndex. Whenever clicked row index is equal to selectedRowIndex, the class will be applied.

Plunker demo

html:

<!-- Add the highlight class in row definiton of md-table -->
<!-- Add click event to pass the selected row index -->

<md-row *cdkRowDef="let row; columns: displayedColumns;" 
         [ngClass]="{'highlight': selectedRowIndex == row.id}"
         (click)="highlight(row)">
</md-row>

css:

.highlight{
  background: #42A948; /* green */
}

ts:

selectedRowIndex = -1;

highlight(row){
    this.selectedRowIndex = row.id;
}

Solution 2:

In the table overview examples page they explain the SelectionModel for handling selections - which incidentally also handles multi-selection.

selection is a SelectionModel defined in your component. I couldn't find any actual documentation for this but the implementation is extremely simple.

selection = new SelectionModel<CustomerSearchResult>(false, null);

The first parameter is allowMultiSelect, so to allow multiple items to be selected at once set it to true. When false the selection model will deselect any existing values when you set a new value.

Then add a click event to select() the row and create your own css class for when the row is selected.

   <mat-table>
        ...

        <mat-row *matRowDef="let row; columns: displayedColumns;"
                 [ngClass]="{ 'selected': selection.isSelected(row)}"
                 (click)="selection.select(row)"></mat-row>

    </mat-table>

The css class I added is below (the sample doesn't mention styling yet) and then you just need to add to your css

.mat-row {
   min-height: 65px;

   &.selected {
       background: #dddddd;
   }
}

If your background color is too dark you'll need to add styles yourself to invert the text color.

To handle selection use the onChange event of selection.

    // selection changed
    this.selection.onChange.subscribe((a) =>
    {
        if (a.added[0])   // will be undefined if no selection
        {
            alert('You selected ' + a.added[0].fullName);
        }
    });

Or alternatively the selected items are in this.selection.selected.

I'm hoping mat-table gets improved for common cases like this and they don't just leave everything up to the developer. Things like keyboard events etc. would be nice to be handled automatically with respect to the selection model.

Solution 3:

I did not have unique identifiers like id column in my table data but this worked for me (material 6):

HTML

 <tr mat-row *matRowDef="let row; columns: displayedColumns" 
     (click)="selectedRow = row" [ngClass]="{ 'selected': row === selectedRow }"> 
 </tr>

or HTML if you want to enable users to unselect on another click

 <tr mat-row *matRowDef="let row; columns: displayedColumns" 
     (click)="selectedRow = selectedRow === row ? null : row" [ngClass]="{ 'selected': row === selectedRow }"> 
 </tr>

add variable to TS

selectedRow;

(S)CSS

.selected {
  background-color: red;
}

If you want to do more things than just styling when selecting a row, replace (click)="selectedRow = row" with (click)="selectRow(row)" and add this function to your ts:

selectRow(row) {
    this.selectedRow = row;
    // more stuff to do...
}