7

Link to stackblitz

I have common components with angular material table (the structure is totally the same). So I want to use ng-content and change some columns:

@Component({
  selector: 'table-basic-example',
  styleUrls: ['table-basic-example.css'],
  templateUrl: 'table-basic-example.html',
})
export class TableBasicExample {
  displayedColumns = ['test', 'name'];
  dataSource = new MatTableDataSource<Element>(ELEMENT_DATA);
}

const ELEMENT_DATA: { name: string } = [
  {name: 'Hydrogen'},
  {name: 'Helium'},
  {name: 'Lithium'},
  {name: 'Beryllium'},
  {name: 'Boron'},
];
<div class="example-container mat-elevation-z8">
  <mat-table #table [dataSource]="dataSource">

    <!-- Position Column -->
    <ng-container matColumnDef="test">
      <mat-header-cell *matHeaderCellDef>Test</mat-header-cell>
      <mat-cell *matCellDef="let element">

        <ng-content select="[test]"></ng-content>

      </mat-cell>
    </ng-container>

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

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

That is why I want to use it like a layout and project some data. So I have another component:

<table-basic-example>

  <div test>
    test
  </div>

</table-basic-example>

But the result is quite strange. I got projection just in the last row.

enter image description here

Link to stackblitz

Stepan Suvorov
  • 25,118
  • 26
  • 108
  • 176
Nataliya U
  • 141
  • 2
  • 6

2 Answers2

9

You should use ng-template with ngTemplateOutlet. Below worked for me.

Here is why ng-content may not work angulars-content-projection-trap-and-why-you-should-consider-using-template-outlet-instead

@Component({
  selector: 'table-basic-example',
  styleUrls: ['table-basic-example.css'],
  templateUrl: 'table-basic-example.html',
})
export class TableBasicExample {
  @Input() templateRef: TemplateRef<any>;
  displayedColumns = ['test', 'name'];
  dataSource = new MatTableDataSource<Element>(ELEMENT_DATA);
}

const ELEMENT_DATA: { name: string } = [
  {name: 'Hydrogen'},
  {name: 'Helium'},
  {name: 'Lithium'},
  {name: 'Beryllium'},
  {name: 'Boron'},
];

<div class="example-container mat-elevation-z8">
  <mat-table #table [dataSource]="dataSource">

    <!-- Position Column -->
    <ng-container matColumnDef="test">
      <mat-header-cell *matHeaderCellDef>Test</mat-header-cell>
      <mat-cell *matCellDef="let element">

        <!-- using ng-template with ngTemplateOutlet instead of ng-content -->
        <ng-template [ngTemplateOutlet]="templateRef"></ng-template>

      </mat-cell>
    </ng-container>

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

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

<table-basic-example>

  <div test [templateRef]="columnTemplateRef">
    <ng-template #columnTemplateRef>
      test
    </ng-template>
  </div>

</table-basic-example>
cjkumaresh
  • 109
  • 1
  • 5
  • It was quite useful for me, but what happens if your template depends on "element" I mean, something like ? – cucuru Oct 05 '18 at 10:52
  • Any solution about this ? I mean how to get 'element' any templateRef ? – Laurent B Sep 15 '19 at 09:47
  • 1
    this should be possible using **ngTemplateOutletContext**. Eg: [https://stackoverflow.com/a/48515379/3928806](https://stackoverflow.com/a/48515379/3928806) – cjkumaresh Sep 16 '19 at 11:26
  • 2
    THe code gives error: Can't bind to 'templateRef' since it isn't a known property of 'div'. – Tom Smykowski Mar 09 '20 at 09:43
1

slightlty modifed the above solution to fix "Can't bind to 'templateRef' since it isn't a known property of 'div'", it may help someone with same scenario.

Stackblitz