How to use a ternary expression inside Angular Material Datatable interpolation to display html

2.8k views Asked by At

I have an Angular Material Datatable setup in my project. My project uses several tables to display various dataSources (clients, providers, trainees, companies) so my aim is to use one datatable, in a component and pass the data, columns and such in dynamically from the given services.

<ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
  <th mat-header-cell *matHeaderCellDef mat-sort-header> <span  style="text-transform: capitalize">{{ column }}</span> </th>
  <td mat-cell *matCellDef="let element">
    {{  element[column]   }} // I need to use an expression here
  </td>
</ng-container>

My columns are like so

  displayedColumns: string[] = ['name', 'address1', 'city', 'postcode', 'region', 'options'];

So this one block builds the full table contents dynamically. You notice I have the options column at the end. This field is not present in the datasource, it is to accommodate a button group so I can offer features such as delete or edit the respective row.

I cannot use a structural directive on the 'mat-cell' element as it already has a *matCellDef attributed. So I figured I could write a simple ternary expression within the interpolation braces to check if the column has the 'options' column-header and switch out the would-be data for my buttons.

<ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
  <th mat-header-cell *matHeaderCellDef mat-sort-header> <span  style="text-transform: capitalize">{{ column }}</span> </th>
  <td mat-cell *matCellDef="let element">
    {{  column == 'options' ? '<button mat-raised-button color="accent">Edit</button>' : element[column]   }}
  </td>
</ng-container>

But my IDE complains of an 'unclosed string literal' immediately after I open the template literal to write the button and when rendered on the screen, it gives no errors but makes a fine mess of my table

Wonky Table

Yet if I do not return any HTML element from the ternary, it I get no errors and the table does as I'd expect

{{  column == 'options' ? 'options column' : element[column]   }}

Desired Result

I also tried calling a function from the ternary which returned the html into the template but it gets escaped.

Can anyone advise on how I can render a button in the rows that pass my ternary condition?

"@angular/material": "^7.0.3",
"@angular/core": "~7.0.0",

TIA

2

There are 2 answers

1
User3250 On BEST ANSWER

You can use ngIf and else syntax as below:

<button *ngIf="column == 'options';else other" mat-raised-button color="accent">Edit</button>
<ng-template #other>{{element[column]}}</ng-template>
2
Rahul On

Yeah that's the beauty of structural directive you cannot have two directive in a same tag - but you can wrap a directive into another

<ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
  <th mat-header-cell *matHeaderCellDef mat-sort-header> <span  style="text-transform: capitalize">{{ column }}</span> </th>
  <ng-container *ngIf="column != 'options'">
     <td mat-cell *matCellDef="let element">
       {{  element[column]   }} // I need to use an expression here
     </td>
  </ng-container>
  <ng-container *ngIf="column === 'options'">
     <td mat-cell *matCellDef="let element">
       <button mat-raised-button color="accent">Edit</button>
     </td>
  </ng-container>
</ng-container>

This is the one way otherwise you can use if and else

<ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
      <th mat-header-cell *matHeaderCellDef mat-sort-header> <span  style="text-transform: capitalize">{{ column }}</span> </th>
      <ng-container *ngIf="column != 'options'; else opt">
         <td mat-cell *matCellDef="let element">
           {{  element[column]   }} // I need to use an expression here
         </td>
      </ng-container>
      <ng-template #opt>
         <td mat-cell *matCellDef="let element">
           <button mat-raised-button color="accent">Edit</button>
         </td>
      </ng-template>
    </ng-container>