Taison Morris
Taison Morris

Reputation: 888

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

Upvotes: 75

Views: 118897

Answers (8)

Carnaru Valentin
Carnaru Valentin

Reputation: 1875

I have same request for all projects and I've created this directive:

import { Directive, ElementRef, HostListener, Input } from "@angular/core";
 
@Directive({
    selector: '[toggleActiveStyle]'
})
export class ToggleActiveStyleDirective {
    prevElement: HTMLElement;
 
    @Input() addActiveCSSClass: boolean;
 
    constructor(private el: ElementRef) {}
 
    @HostListener('click') onClick () {
        setTimeout(() => {
            for(let i = 0; i < this.el.nativeElement.parentElement.children.length; i++) {
                this.el.nativeElement.parentElement.children[i].style.background = '';
            }
            if(this.addActiveCSSClass) {
                this.el.nativeElement.style.background = 'white';
            }
            else {
                this.el.nativeElement.style.background = '#cccccc';
            }
        });
    }
}

And in HTML add:

And in component to can set: addBg = true/false;

Upvotes: 0

Nehal
Nehal

Reputation: 13307

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

Upvotes: 104

Jaydeep Nayak
Jaydeep Nayak

Reputation: 1

This will allow you to select multiple rows if the row is not previously selected and on clicking again it will deselect it.

HTML

<mat-row *matRowDef="let row; columns: displayedColumns;"
  (click)="findOut(row)"[style.background]="highlightedRows.indexOf(row) != -1 ? 'lightgrey' : ''"></mat-row>

Type Script

Create an array

highlightedRows = [];

Define the findOut function

findOut(row){
  if(this.highlightedRows.indexOf(row) === -1){
    this.highlightedRows.push(row);
    }
    else{
    
      this.highlightedRows[this.highlightedRows.indexOf(row)] = -1;
    }
    
  }

Upvotes: 0

Zuzze
Zuzze

Reputation: 241

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

Upvotes: 23

noel
noel

Reputation: 452

Building on Zuzzie's answer, which is the solution that mostly worked for me, I did the following:

HTML:

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

add variable to TS:

selectedRow : boolean;

add this function to TS:

onRowClicked(row) {

   if(!this.selectedRow)
   {
     this.selectedRow = row;
   }   
   else
   {
     this.selectedRow = row;
   }

}

(S)CSS

.selected {
  background-color: red;
}

Upvotes: 2

Simon_Weaver
Simon_Weaver

Reputation: 146188

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.

Upvotes: 51

Priya
Priya

Reputation: 67

For material": "^7.0.3",

use the css name in html, without the single quote, to highlight the row

 .mat-row.highlighted {
  background: lightblue;
  }


<tr mat-row *matRowDef="let row; columns: displayedColumn;" 
[ngClass]="{highlighted: selectedRowIndex == row.id}"  (click)="highlight(row)" > 
</tr>


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

Upvotes: 4

Nick Landkamer
Nick Landkamer

Reputation: 51

So, I ran into this issue as well. I'm using the newer 'mat-' instead of 'md-', but I'm GUESSING it will be about the same...

<mat-row
    *matRowDef="let row; columns: myColumns; let entry"
    [ngClass]="{ 'my-class': entry.someVal }">
</mat-row>

I didn't find that anywhere, I just tried it and it happened to work out, so I hope that's right. The big thing was tagging 'let entry' to the end of the other matRowDef stuff. Sorry I'm so late to the party. Hopefully this does someone some good.

Upvotes: 5

Related Questions