Angular无法使用ViewChild时如何在事件处理器内获取动态组件实例
Angular 动态组件场景下事件处理器获取组件实例的实现
原有写法拿到undefined的核心原因
- 你遇到的传值为空的问题,本质和动态组件的视图挂载时序有关:这类嵌在模板内部的动态生成组件,基本都是被
*ngIf、*ngFor、<ng-template>这类结构指令包裹在嵌套视图块里的。Angular在首次解析模板绑定表达式时会做一次绑定快照,此时嵌套视图还没完成挂载,#e对应的模板引用还没被初始化赋值,直接在同元素的click事件表达式里传递,自然就会拿到undefined。 - 很多人说这类动态组件用不了
ViewChild,其实是参数配错了:默认带static: true配置的话,会强制在首次变更检测执行前读取引用,这时候动态组件还没被创建出来,当然拿不到实例。
可直接落地的实现方案
- 适配动态视图的引用初始化时机,调整模板事件传参
很多人遇到undefined就乱改模板取值逻辑,其实只要遵守Angular的引用传递规则,原有写法基本不需要大改,只要别对引用做提前取值就行:
这里要明确框架的默认规则:自定义组件标签上挂的模板引用变量,默认就指向组件类的实例本身,根本不会返回DOM元素,也不需要额外去拆<!-- 原写法不需要改,只要注意别提前拆解引用 --> <example #e (click)="onExample(e)" />nativeElement、instance这类属性。之前传undefined,多半是你在组件还没渲染完成的时候就触发了读取逻辑,等组件真正挂到页面上,用户点击的时候,引用早就完成初始化了。 - 针对通过
ViewContainerRef.createComponent手动创建的动态组件,直接在创建阶段留存实例
这类组件本来就不在你写的静态模板里,根本没必要在模板上绑引用变量。你在调用动态创建API的时候,返回的ComponentRef对象已经包含了完整的组件实例,直接存成类成员就行,完全绕开模板引用的时序问题:private createdExampleComp?: ExampleComponent; // 动态渲染组件的方法 renderDynamicExample() { const compRef = this.viewContainerRef.createComponent(ExampleComponent); // 直接存下组件实例,后续事件触发时直接读 this.createdExampleComp = compRef.instance; } // 点击事件处理函数 onExampleClick() { // 这里拿到的就是完整的组件实例,没有任何DOM元素包裹 const targetComp = this.createdExampleComp; } - 动态场景下的ViewChild正确配置
如果还是想用ViewChild方式获取引用,只要把静态配置关掉,Angular就会在每轮变更检测完成后自动更新引用值,哪怕组件是动态嵌在模板内部的也能正常拿到:// 适配动态组件的ViewChild写法 @ViewChild('e', { static: false }) exampleCompInstance?: ExampleComponent; onExampleClick() { // 点击事件触发时,变更检测已经跑完了,这个引用早就被赋值了 const targetComp = this.exampleCompInstance; }
内容的提问来源于stack exchange,提问作者justin.m.chase
相关产品推荐
相关产品推荐

