19

I'm using Angular Material 7 tables (mat-table). What I want to achieve is a link for a whole row in order to show a detail page.

The requirement is to show a real link which can be opened in a new tab, so the usual (click)-event does not work.

I achieved to add a link around the content of every mat-cell, but as I have a lot of columns this is not a good solution.

Is there a nice way to convert every mat-row to a link (href)?

Edit: I removed my example as correct answer was given below.

Laess3r
  • 944
  • 1
  • 9
  • 13

4 Answers4

23

Add routerLink to mat-row

<mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="'transaction/' + row.id" class="row-hover"></mat-row>

OR

You could add click event and custom css class to mat-row:

<mat-row *matRowDef="let row; columns: displayedColumns;"
(click)="navigateTo(row)" class="row-hover"></mat-row>

then in .ts file:

import { Router } from '@angular/router';
...
...
constructor(private router: Router) {}
...
navigateTo(row: any) {
  this.router.navigate(['/maintenance/data/'+row.id]);
} 

And add css class

.row-link:hover {
  background-color: rgba(0, 0, 0, .05);
  cursor: pointer;
}
Marius
  • 255
  • 1
  • 5
  • 2
    Thanks, but this is still not a real link. I tried to create a wrapper directive, but as matRowDef is already a directive, it became very difficult. – Laess3r Dec 14 '18 at 08:31
  • 11
    **None** of these solutions is accessible. One should be allowed to open a link in a new tab, or to copy the URL with right-click. However, that's impossible with this solution. It's also not possible to open the link by focusing it with the keyboard and pressing Enter. This is bad practice. – Aloso Mar 31 '20 at 20:23
  • 1
    rounterLink should be declared like this: `[routerLink]="'transaction/' + row.id"` otherwise it won't work – Francisco Bueno May 13 '20 at 14:28
  • please make also sure that the module you are in has imported the RouterModule for the routerLink to work as expected. – SwissCoder Oct 12 '21 at 20:30
  • Perfect answer, however in my CSS I had to use syntax tr.mat-row:hover to get it to work, thanks to answer from Sebastian Castaldi (https://stackoverflow.com/a/57399567/10287733) – Rory Feb 03 '22 at 04:57
19

Well, you can do the classic trick of an empty a tag over the whole row. Simply put the tag into just ONE of ng-containers and give it a custom css rule:

<mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">

  <ng-container matColumnDef="name">
    <mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
    <mat-cell *matCellDef="let element">
      {{element.name}}          
      <a fxFlexFill [routerLink]="'/maintenance/data/'+element.id" class="mat-row-link"></a>
    </mat-cell>
  </ng-container>

  <ng-container matColumnDef="lastname">
    <mat-header-cell *matHeaderCellDef>Last Name</mat-header-cell>
    <mat-cell *matCellDef="let element">          
      {{element.lastname}}
    </mat-cell>
  </ng-container>

  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>

</mat-table>

Then on CSS:

.mat-row{        
    position: relative;
}

.mat-row-link{
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;             
}

Just remember that an empty a tag will make the job, but doesn't comply all the SEO standars...

M.Ortega
  • 206
  • 1
  • 3
  • Thank you very much, it works! I put the css in our global stylesheet, so this is a nice solution for us :-) – Laess3r Jan 21 '19 at 12:08
  • 1
    Edit: The issue with this solution is that the row data cannot be marked any more (to copy-paste data) :-/ – Laess3r Jun 27 '19 at 12:08
  • 3
    This seems like a good way to go, but unfortunately it doesn't work for me. I've added some text (to see where the position goes to), and when I do I see the text at the top of the viewport rather than in the row. Somehow the position:relative is not applying to the `.mat-row` and is scoping to the page. Dont see any other position:relative links up the chain either. – Rick Strahl Nov 09 '19 at 20:59
  • 2
    @RickStrahl same for me. did you find a solution for this? – Ishmeet Dec 04 '19 at 05:34
  • This seems to cover the entire table instead of just the row – Matt Westlake Feb 07 '21 at 03:46
  • What if you have clickable content inside of the table row (e.g. a button)? It should still be clickable and therefore lay itself on top of the a tag. – Sentenza Aug 03 '22 at 08:28
  • 1
    ❗️breaks on current Safari! – Verim Aug 15 '22 at 09:14
  • @Verim did you find any solution so far? – Laess3r Nov 11 '22 at 11:45
8

You can wrap the whole row in an a-tag and add the routerLink to that. With that solution you'll get the native link handling. I'm using the cdk-table but I guess that should also work for the angular material table.

My solution looks as follow:

<cdk-table [dataSource]="data">
    ...
    <a *cdkRowDef="let row; columns; columns" [routerLink]="['path', row.id]">
        <cdk-row></cdk-row>
    </a>
</cdk-table>
andii1997
  • 139
  • 2
  • 5
0

You could add the row like defined in the Anuglar Material Docs. That way you can add the [routerLink] to the entire row instead of individual cells.

Smallwater
  • 364
  • 2
  • 10
  • I changed from "mat-table" to "table mat-table" to try your link. Using only [routerLink] makes the rows clickable, but the browser doesn't detect this as real links. I'd have to somehow wrap the rows in an "a" tag. – Laess3r Dec 13 '18 at 14:43