For an Angular application I want to create a table component that wraps a PrimeNG table. For this table component it should be possible to define a body template. Therefore I need to somehow forward the body template to the wrapped PrimeNG table, but I cannot figure out how to achieve that.
Following is a simplified version of my table component that wraps the PrimeNG table:
import { AfterContentInit, Component, ContentChildren, Input, QueryList, TemplateRef } from '@angular/core';
import { PrimeTemplate } from "primeng/api";
@Component({
selector: 'app-my-table',
template: `
<p-table
*ngIf="bodyTemplate"
[value]="value"
>
<ng-template pTemplate="caption">
{{title}}
</ng-template>
<ng-template pTemplate="header">
<tr>
<th *ngFor="let h of headers">{{h}}</th>
</tr>
</ng-template>
<!-- here should bodyTemplate go, but how? -->
<ng-template pTemplate="body" [ngTemplateOutlet]="bodyTemplate"></ng-template>
</p-table>
`
})
export class MyTableComponent implements AfterContentInit {
@ContentChildren(PrimeTemplate) templates!: QueryList<PrimeTemplate>;
@Input() title: string = '';
@Input() headers: string[] = [];
@Input() value: any[] = [];
bodyTemplate: TemplateRef<any> | undefined;
ngAfterContentInit() {
this.templates.forEach((item) => {
switch (item.getType()) {
case 'body':
this.bodyTemplate = item.template;
break;
}
});
}
}
And the following is how it should be used (I use the pTemplate directive to get the TemplateRef for the body template, in the same way as PrimeNG does that).
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<app-my-table
title="My table"
[headers]="headers"
[value]="data"
>
<ng-template pTemplate="body" let-item>
<tr>
<td>{{item.a}}</td>
<td>{{item.b | uppercase }}</td>
<td>{{item.c | percent }}</td>
</tr>
</ng-template>
</app-my-table>`,
})
export class AppComponent {
headers = ['A', 'B', 'C'];
data = [
{ a: 'a', b: 'b', c: 0.0},
{ a: 'a', b: 'b', c: 0.1},
{ a: 'a', b: 'b', c: 0.2},
{ a: 'a', b: 'b', c: 0.3},
{ a: 'a', b: 'b', c: 0.4},
{ a: 'a', b: 'b', c: 0.5},
];
}
I tried to insert bodyTemplate
with <ng-template pTemplate="body" [ngTemplateOutlet]="bodyTemplate"></ng-template>
, but that doesn't work. It might be an issue with a missing context (the error reads "Cannot read properties of undefined (reading 'a')"
), but maybe I am just doing it wrong :).
Does anyone know how this can be achieved?
ngTemplateOutlet
use with ng-container
not ng-template
should be
<ng-container pTemplate="body" *ngTemplateOutlet="bodyTemplate; context: { $implicit: row}"></ng-container>
and wrap it inside p-table
default body template
<ng-template pTemplate="body" let-row>
<ng-template pTemplate="body" let-row> <ng-container pTemplate="body" *ngTemplateOutlet="bodyTemplate; context: { $implicit: row}"></ng-container> </ng-template>
Demo here