当前位置: 首页 > Web前端 > JavaScript

动态创建@ViewChild导致运行时错误分析

时间:2023-03-27 00:12:01 JavaScript

本文讨论问题的代码位于Github:https://github.com/wangzixi-d...问题描述我的Component代码如图下图:使用dependenciesInject,引入ViewContainerRef,使其createEmbeddedView方法可以在运行时动态创建实例。使用@ViewChild获取在ComponentHTML源码中定义的id为tpl的模板实例,type为TemplateRef。组件的HTML源代码:

你好,ng-template!
然而,当启动应用程序时,出现运行时错误:ERRORTypeError:Cannotreadpropertiesofundefined(reading'createEmbeddedView')atViewContainerRef.createEmbeddedView(core.js:10190:45)atNgTemplateComponent.push.8YnP.NgTemplateComponent.ngAfterViewInit(ng-template.component.ts:20:20)atcallHook(core.js:3281:18)atcallHooks(core.js:3251:17)atexecuteInitAndCheckHooks(core.js:3203:9)在refreshView(core.js:7451:21)在renderComponentOrTemplate(core.js:7494:9)在tickRootContext(core.js:8701:9)在detectChangesInRootView(core.js:8726:5)在RootViewRef.detectChanges(core.js:9991:9)问题分析在上面的调用上下文中,有一个栈帧就是我们应用的代码:ngAfterViewInit(ng-template.component.ts:20:20)设置断点在其方法中,运行时发现this.tplRef为空。此错误是由于在值未定义的变量上调用createEmbeddedView引起的。问题转化为:this.tplRef的赋值逻辑是什么?在ngOnInit时,此属性仍未定义:我们将鼠标悬停在@ViewChild上以查看其描述:更改检测器将在视图的DOM中查找与选择器匹配的第一个元素或指令。如果视图的DOM更改并且出现与选择器匹配的新子节点,则此属性将被更新。发现输入参数是一个选择器。在这种情况下,我传入的选择器是id选择器:tpl根据Angular官网文档,这意味着在我的HTML模板文件中,tpl之前应该修改为#:解决方法是在tpl之前添加#:总结如果我们想进一步观察视图查询是如何根据传入的选择器tpl走到dom树中查找到的节点的,可以添加如下代码,即@ViewChild和set函数的组合。@ViewChild('tpl')设置thisNamedoesnotMatter(v:TemplateRef){console.log('Jerry');this.tplRef=v;}通过调试,发现在Chrome开发者工具中不会显示视图查询的执行过程,只会显示一个dummy的XXX(Componentname)_Query调用上下文。set函数中的入参v表示id为tpl的Template实例。