MaterialTable migration guide

The Angular Material Table offers many useful functionalities, such as pagination or sorting. Moreover, you can easily add inputs into the columns and it means less maintenance effort for us. In order to migrate to the mat-table, you need the terra-components version 5.4.0 or higher.

Switching to the mat-table (Angular Material Table)

First of all, add the MatTableModule to your module. In order to switch to the mat-table, wrap the table into a <div> container by using the .mat-table-container class.

  <div class="mat-table-container">
    <terra-data-table...>
  </div>

In a next step, replace the <terra-data-table> by the <mat-table> (or <table mat-table>).

<div class="mat-table-container">
  <table mat-table...>
    <terra-no-result-notice...>
  </table>
</div>

Then place the <terra-no-result-notice> below the <div> container.

<div class="mat-table-container">
  <table mat-table...>
  </table>
  <terra-no-result-notice...>
  </terra-no-result-notice>
</div>

Transfer the column definition to a string-based array.

public _columnList:Array<string> =
       ['id', 'firstName', 'lastName'];
<div class="mat-table-container">
  <table mat-table...>
    <tr mat-header-row *matHeaderRowDef="_columnList"></tr>
  </table>
  <terra-no-result-notice...>
  </terra-no-result-notice>
</div>

Afterwards, add all required cells to the template. Note that these have to be the same as in the column definition array.

<div class="mat-table-container">
  <table mat-table...>
    <ng-container matColumnDef="id">
      <th mat-header-cell *matHeaderCellDef>ID</th>
      <td mat-cell *matCellDef="let contact">
        
      </td>
    </ng-container>
     <ng-container matColumnDef="firstName">
       <th mat-header-cell *matHeaderCellDef>First name
       <td mat-cell *matCellDef="let contact">
         
       </td>
     </ng-container>
     <ng-container matColumnDef="lastName">
       <th mat-header-cell *matHeaderCellDef>Last name</th>
       <td mat-cell *matCellDef="let contact">
         
       </td>
     </ng-container>
     <tr mat-header-row *matHeaderRowDef="_columnList"></tr>
     <tr mat-row *matRowDef="let contact; columns: _columnList">
     </tr>
  </table>
  <terra-no-result-notice...>
  </terra-no-result-notice>
</div>

Optional: Create SelectionModel in the .ts file, add the selection column to the column list and replace table.selectedRowList by selection.selected in order to get the group function to work again. An example implementation of the check box toggle logic can be found in the Angular Material documentation. Don’t forget to add the MatCheckboxModule to your module.

public _columnList:Array<string> =
             ['select', 'id', 'firstName', 'lastName'];

/**
* @param _multiple defines if multiple selections are
         possible or not
* @param initiallySelectedValues is an array of
         ContactInterfaces, which are preselected
*/
public _selection:SelectionModel<ContactInterface> =
             new SelectionModel<ContactInterface>(true, []);
<div class="mat-table-container">
  <table mat-table>
    <ng-container matColumnDef="select">
      <th mat-header-cell *matHeaderCellDef>
        <mat-checkbox
          (change)="$event ? _masterToggle() : null"
          [checked]="_selection.hasValue() && _isAllSelected()"
          [indeterminate]="_selection.hasValue() && !_isAllSelected()">
        </mat-checkbox>
      </th>
      <td mat-cell *matCellDef="let contact">
        <mat-checkbox
          (click)="$event.stopPropagation()"
          (change)="$event ? _selection.toggle(contact) : null"
          [checked]="_selection.isSelected(contact)">
        </mat-checkbox>
      </td>
    </ng-container>
    ...
    <tr mat-header-row *matHeaderRowDef="_columnList"></tr>
    <tr mat-row *matRowDef="let contact; columns: _columnList" [class.selected]="_selection.isSelected(contact)">
  </table>
  <terra-no-result-notice...>
  </terra-no-result-notice>
</div>

Creating a DataSource

Create a DataSource that extends the desired DataSource:

Keep in mind that extra steps are required (explained below).

First, implement the request method.

public request(requestParams:RequestParameterInterface):Observable<TerraPagerInterface<ContactInterface>>
{
   return this.contactService.getContacts(requestParams);
}

Afterwards, add DataSource to the <mat-table>.

<div class="mat-table-container">
  <table mat-table [dataSource]="_dataSource">
    ...
  </table>
</div>

Optional: The data of the search result is available in the DataSource and can be used to display or hide containers such as the <terra-no-result-notice> or disable the <mat-paginator> (see chapter 4).

<div...>
  <table mat-table [dataSource]="_dataSource">
  </table>
  <terra-no-result-notice *ngIf="_dataSource.data.length === 0" ...>
  </terra-no-result-notice>
</div>

Optional: Use the search() method to trigger the REST call (e.g. in the <terra-no-result-notice>).

Creating a TerraFilter (optional)

This is useful if you have filters and works with all four DataSource variations.

First, create a public field for the filter in the FilterComponent.

public filter:TerraFilter<ContactFilterInterface> = new TerraFilter<ContactFilterInterface>();

In order to trigger the search, use the search() method from the filter.

<tc-filter (search)="filter.search()">
  ...
</tc-filter>

Replace the dataTableService.filterParameter by filter.filterParameter.

<tc-filter (search)="filter.search()">
  <mat-form-field class="example-form-field">
    <mat-label>Name</mat-label>
    <input matInput type="text"
      [(ngModel)]="filter.filterParameter.name">
  </mat-form-field>
</tc-filter>

Then pass the filter to the dataTable (e.g. in the overview).

<terra-2-col mobileRouting>
  <ptb-filter #filter left></ptb-filter>
  <ptb-table [filter]="filter?.filter" right></ptb-table>
</terra-2-col>

In the data table component, you now need to assign the filter to the DataSource.

@Input()
public filter:TerraFilter<ContactFilterInterface>;
...
public ngOnInit():void
{
  this._dataSource.filter = this.filter;
}

Using a paginator (optional)

First of all, add the MatSelectModule and the MatPaginatorModule to your module. In case the defaultPagingSize logic (to save the default paging size) exists, move it to the DataSource.

In HTML:

<mat-paginator [pageSize]="dataSource.pagingSize" [pageSizeOptions]="[3, 25, 50, 100]"></mat-paginator>

In DataSource:

export class ContactsTableDataSource extends TablePagingSortingDataSource<ContactInterface>
{
   public pagingSize:number;

   private readonly uiConfigKey:UiConfigEnum = UiConfigEnum.contactsTablePagerUiConfig;

   constructor(private contactsService:ContactsService,
               private globalRegistry:GlobalRegistryService,
               private uiConfigService:UiConfigService)
   {
       super();

       if(!isNullOrUndefined(globalRegistry.userData.uiConfig[this.uiConfigKey]))
       {
           this.pagingSize = globalRegistry.userData.uiConfig[this.uiConfigKey][0];
       }
   }

   public request(requestParams:RequestParameterInterface):Observable<TerraPagerInterface<ContactInterface>>
   {
       if(this.paginator.pageSize !== this.pagingSize)
       {
           this.savePagerSettingsToUiConfig(this.paginator.pageSize);
       }

       return this.contactsService.getContacts(requestParams);
   }

   private savePagerSettingsToUiConfig(itemsPerPage:number):void
   {
       this.uiConfigService.updateUiConfigValue(this.uiConfigKey, itemsPerPage).subscribe(() =>
       {
           this.pagingSize = itemsPerPage;
       });
   }
}

In order to use a paginator, extend the DataSource of the TablePagingDataSource.

Then add the mat-paginator to the template.

<div ...>
  <mat-paginator
    [pageSize]="5"
    [pageSizeOptions]="[5, 10, 25, 50]"
    [disabled]="_dataSource.data.length === 0">
  </mat-paginator>
  <table mat-table [dataSource]="_dataSource">
    ...
  </table>
</div>

In a next step, create a ViewChild in the .ts file.

@ViewChild(MatPaginator, {static: true})
public paginator:MatPaginator;

Afterwards, assign the mat-paginator to the dataSource.

public ngOnInit():void
{
   ...
   this._dataSource.paginator = this.paginator;
}

Make sure that the response can handle pagination.

public getContacts(
  requestParams:any
):Observable<TerraPagerInterface<ContactInterface>>
{
   return this
            .http
            .get<TerraPagerInterface<ContactInterface>>(
              this.url,
              {params:  createHttpParams(requestParams)
            );
}

Using sorting (optional)

First of all, add the MatSortModule to your module. In order to use sorting, extend the DataSource of TableSortingDataSource and add the matSort directive to the <table mat-table> or <mat-table>.

<div ...>
   <mat-paginator ...></mat-paginator>
  <table mat-table
         matSort
         matSortActive="id"
         matSortDirection="desc"
         [dataSource]="_dataSource" >
  </table>
</div>

In a next step, create a ViewChild in the .ts file.

@ViewChild(MatSort, {static: true})
public sort:MatSort;

Afterwards, assign the mat-sort to the dataSource.

public ngOnInit():void
{
   ...
   this._dataSource.sort = this.sort;
}

Using sorting and paginator (optional)

To use both sorting and paginator, first extend the DataSource of TablePagingSortingDataSource. To implement both, carry out the steps in chapter 4 and 5 (except for extending the data source).

Deleting old services

Before deleting the data table service, check the implementation and make sure not to forget anything. Once you have done so, you can delete the data table service.

Is this article helpful?

 

Thank you for your Feedback

you can close this field now!