如何将ngTemplate传递给封装的PrimeNG Table组件
问题:Angular封装PrimeNG Table时自定义Body模板上下文丢失
在Angular应用中封装PrimeNG Table组件,期望支持外部自定义body模板,但将外部模板转发给内部PrimeNG Table时出现错误:Cannot read properties of undefined (reading 'a'),原因是模板上下文未正确传递。
封装组件代码
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> <!-- 此处尝试插入body模板但上下文丢失 --> <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; } }); } }
组件使用代码
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}, ]; }
解决方案
问题核心是:PrimeNG的pTemplate="body"模板会自动接收内部传递的上下文(包含当前行数据$implicit、行索引rowIndex等变量),直接使用ngTemplateOutlet时未转发这些上下文,导致外部模板的let-item无法获取有效数据。
修改封装组件的模板部分
将原来的模板插入代码替换为以下内容,完整转发PrimeNG提供的上下文:
<ng-template pTemplate="body" let-ctx="*"> <ng-template [ngTemplateOutlet]="bodyTemplate" [ngTemplateOutletContext]="ctx"></ng-template> </ng-template>
若只需传递部分变量,也可显式指定:
<ng-template pTemplate="body" let-item let-rowIndex="rowIndex"> <ng-template [ngTemplateOutlet]="bodyTemplate" [ngTemplateOutletContext]="{ $implicit: item, rowIndex: rowIndex }"> </ng-template> </ng-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> <!-- 正确转发上下文的body模板插入 --> <ng-template pTemplate="body" let-ctx="*"> <ng-template [ngTemplateOutlet]="bodyTemplate" [ngTemplateOutletContext]="ctx"></ng-template> </ng-template> </p-table>
原理说明
let-ctx="*"接收PrimeNG传递给body模板的完整上下文对象,包含$implicit(对应外部模板的let-item)、rowIndex、rowData等所有PrimeNG提供的模板变量。- 通过
[ngTemplateOutletContext]="ctx"将上下文传递给外部模板,确保item等变量能被正确读取。
内容的提问来源于stack exchange,提问作者Bastiaan van den Berg
相关产品推荐
相关产品推荐

