Angular 14动态创建组件报错:Cannot read properties of undefined (reading 'createComponent')
问题
我有一个Header组件,想要在用户登录时动态创建HeaderUserMenu组件,但运行时报错。为了排查模板问题,我同时加了静态和动态组件,静态组件能正常工作,但动态组件就是跑不起来。
HeaderComponent.ts 代码
export class HeaderComponent implements OnInit, OnDestroy, AfterViewInit { private dynamicHeaderUserMenu: ViewContainerRef; @ViewChild('appHeaderUserMenu', { read: ViewContainerRef, static: true }) set appHeaderUserMenu( vcRef: ViewContainerRef ) { if (vcRef) { this.dynamicHeaderUserMenu = vcRef; } } ngAfterViewInit(): void { //initialize dynamic components this.subs.push( this.isLoggedIn$.subscribe((loggedIn) => { if (loggedIn) { const createRef = this.dynamicHeaderUserMenu.createComponent(HeaderUserMenuComponent); } }) ); }
HeaderComponent.html 代码
<div *ngIf="showUMenu" f> <app-header-user-menu></app-header-user-menu> <ng-template #appHeaderUserMenu></ng-template> </div>
报错信息ERROR TypeError: 无法读取未定义的属性 'createComponent'
解决方案
问题根源
dynamicHeaderUserMenu 没被正确赋值,因为模板里的 <ng-template #appHeaderUserMenu> 被包在带 *ngIf="showUMenu" 的 div 里了。如果 showUMenu 初始值是 false,这个模板根本不会被渲染,@ViewChild 拿不到对应的 ViewContainerRef,后面调用 createComponent 自然就会触发空指针错误。
修复方法
- 调整模板位置:把
<ng-template #appHeaderUserMenu>移到*ngIf外面,保证组件初始化时Angular能找到它:
<ng-template #appHeaderUserMenu></ng-template> <div *ngIf="showUMenu" f> <app-header-user-menu></app-header-user-menu> </div>
要是你需要动态组件也受 showUMenu 控制,可以保留原来的结构,但修改 @ViewChild 的 static 配置,并且在赋值回调里处理组件创建:
@ViewChild('appHeaderUserMenu', { read: ViewContainerRef, static: false }) set appHeaderUserMenu( vcRef: ViewContainerRef ) { if (vcRef) { this.dynamicHeaderUserMenu = vcRef; // 这里可以根据当前登录状态直接创建组件,避免在订阅里用未初始化的变量 if (this.isLoggedIn) { this.dynamicHeaderUserMenu.createComponent(HeaderUserMenuComponent); } } }
- 加空值校验:不管怎么调整,调用
createComponent前先确认dynamicHeaderUserMenu已经初始化,防止报错:
if (loggedIn && this.dynamicHeaderUserMenu) { const createRef = this.dynamicHeaderUserMenu.createComponent(HeaderUserMenuComponent); }
- 清理订阅:别忘了在
ngOnDestroy里取消isLoggedIn$的订阅,避免内存泄漏:
ngOnDestroy(): void { this.subs.forEach(sub => sub.unsubscribe()); }
内容的提问来源于stack exchange,提问作者Balalayka
相关产品推荐
相关产品推荐

