DEV Community

John Peters
John Peters

Posted on • Updated on

Material Table Explained

A minimal example to get you up and running fast...

<table mat-table [dataSource]="collection">
   <ng-container matColumnDef="setting">
      <th mat-header-cell *matHeaderCellDef>Setting</th>
      <td mat-cell *matCellDef="let setting">
         {{ setting.id }}
      </td>
   </ng-container>
   <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
   <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
Enter fullscreen mode Exit fullscreen mode

The dataSource

The mat-table directive allows us to set a datasource...

<table mat-table [dataSource]="collection">
Enter fullscreen mode Exit fullscreen mode

which is an Array of something in our Typescript file for this page.

Column Definitions

The Material Table focuses on a columnar first concept using ng-containers.

 <ng-container matColumnDef="setting">
      <th mat-header-cell *matHeaderCellDef>Setting</th>
      <td mat-cell *matCellDef="let setting">
         {{ setting.propName }}
      </td>
   </ng-container>
Enter fullscreen mode Exit fullscreen mode

The ng-container uses the "matColumnDef" directive (a column definition) with the name of 'setting'. This column of the table will have a header with the value "Setting" shown. Each row of data will show the value of setting.propName.

At render time, each material column definition is called with each item within the dataSource. But nothing will show unless the next two items are defined.

Table Rows

The column definitions only took care of the TH and the TD for each column header. Now we have to define how to render each row. The all important displayedColumns is used as a mat-header-row and a mat-row. I'm not fully aware of why we need two TR items.


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

Enter fullscreen mode Exit fullscreen mode

Here we see each TR pointing to displayedColumns which is an array of the names we assigned to each columndef we want to show.

Injecting Content Renderers

Can we swap in other custom controls? Yes..
If we substitute a custom component as in "app-setting" below, the content of the TD will pass a setting value to the app-setting html element via the [setting] property it contains.

<table mat-table [dataSource]="collection">
 <ng-container matColumnDef="setting">
      <th mat-header-cell *matHeaderCellDef>Setting</th>
      <td mat-cell *matCellDef="let setting">
         <app-setting [setting]="setting"></app-setting>
      </td>
   </ng-container>
   <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
   <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
 </table>
Enter fullscreen mode Exit fullscreen mode

The material table's 1st column will look like this when we name the columndef "Setting" and have only one value in:

Alt Text

We've injected our own rendering logic for each row of the Table.

Next up: Render HTML elements which are editable on each row of a Material Table.

JWP2020

Top comments (1)

Collapse
 
arachnetech profile image
David Miller

I'm confused by the syntax of: <tr mat-row *matRowDef="let row; columns: displayedColumns"> - what is the expression in matRowDef doing here exactly?