Angular表单构建:如何在ng-container中用对象属性作为templateRef?
问题:Angular中通过配置动态指定ngTemplateOutlet模板报错
错误信息
ERROR TypeError: templateRef.createEmbeddedViewImpl is not a function at ViewContainerRef.createEmbeddedView (core.mjs:19896:37) at NgTemplateOutlet.ngOnChanges (common.mjs:3951:46) at NgTemplateOutlet.rememberChangeHistoryAndInvokeOnChangesHook (core.mjs:2514:14) at callHookInternal (core.mjs:3524:14) at callHook (core.mjs:3555:9) at callHooks (core.mjs:3506:17) at executeInitAndCheckHooks (core.mjs:3456:9) at selectIndexInternal (core.mjs:11954:17) at Module.ɵɵadvance (core.mjs:11937:5) at ModalComponent_ng_template_3_Template (modal.component.html:16:20) handleError @ core.mjs:11752
相关代码
form-build.html
<ng-template #input let-item="item"> <mat-form-field class="example-form-field"> <mat-label>Clearable input</mat-label> <input matInput type="text"> <mat-icon matSuffix svgIcon="heroicons_outline:user-circle"></mat-icon> </mat-form-field> </ng-template> <ng-container *ngTemplateOutlet="template; context: { formConfig: formConfig }"></ng-container> <ng-template #template let-config="formConfig"> <!-- 报错的容器 --> <ng-container [ngTemplateOutlet]="config['perguntaForm'].formFieldType" [ngTemplateOutletContext]="{item: config['perguntaForm']}"></ng-container> <!-- 正常渲染的容器 --> <ng-container [ngTemplateOutlet]="input" [ngTemplateOutletContext]="{item: config['perguntaForm']}"></ng-container> </ng-template>
form-build.ts
@Component({ ...}) export class FormConfig { formConfig: any = { perguntaForm: { formFieldType:'input', type: 'text' }, } }
尝试强制声明类型也无效:
@Component({ ...}) export class FormConfig { formConfig: any = { perguntaForm: { formFieldType:TemplateRef<'input'>, type: 'text' }, } }
问题原因
ngTemplateOutlet要求绑定的是TemplateRef实例,但你在formConfig里给的formFieldType是字符串'input',Angular无法将字符串识别为模板引用,因此抛出createEmbeddedViewImpl is not a function错误。强制声明类型只是TypeScript层面的类型断言,实际值还是字符串,无法解决问题。
解决方案
需要将字符串标识和对应的TemplateRef实例做映射,具体步骤如下:
- 在组件中通过
ViewChild获取模板引用并建立映射:
import { Component, ViewChild, TemplateRef, AfterViewInit } from '@angular/core'; @Component({ ... }) export class FormConfig implements AfterViewInit { @ViewChild('input') inputTemplate!: TemplateRef<any>; formConfig: any = { perguntaForm: { formFieldType:'input', type: 'text' }, }; // 建立字符串到模板引用的映射表 templateMap: Record<string, TemplateRef<any>> = {}; ngAfterViewInit(): void { this.templateMap['input'] = this.inputTemplate; } }
- 在模板中通过映射对象获取对应的TemplateRef:
<ng-template #template let-config="formConfig"> <ng-container [ngTemplateOutlet]="templateMap[config['perguntaForm'].formFieldType]" [ngTemplateOutletContext]="{item: config['perguntaForm']}"></ng-container> <ng-container [ngTemplateOutlet]="input" [ngTemplateOutletContext]="{item: config['perguntaForm']}"></ng-container> </ng-template>
这样就能通过配置中的字符串标识,动态渲染对应的模板了。
内容的提问来源于stack exchange,提问作者Juba
相关产品推荐
相关产品推荐

