动态创建 @ViewChild 导致运行时错误的原因分析
本文讨论问题的代码,位于 Github:https://github.com/wangzixi-diablo/ngDynamic
问题描述
我的 Component 代码如下图所示:
使用依赖注入,引入
ViewContainerRef
,从而可以使用其createEmbeddedView
方法,在运行时动态创建实例。使用
@ViewChild
,获得该 Component HTML 源代码里定义的 id 为 tpl 的模板实例,类型为TemplateRef
。Component 的 HTML 源代码:
<ng-template tpl><div>Hello, ng-template!</div>
</ng-template>
然而启动应用,出现运行时错误:
ERROR TypeError: Cannot read properties of undefined (reading ‘createEmbeddedView’)
at ViewContainerRef.createEmbeddedView (core.js:10190:45)
at NgTemplateComponent.push.8YnP.NgTemplateComponent.ngAfterViewInit (ng-template.component.ts:20:20)
at callHook (core.js:3281:18)
at callHooks (core.js:3251:17)
at executeInitAndCheckHooks (core.js:3203:9)
at refreshView (core.js:7451:21)
at renderComponentOrTemplate (core.js:7494:9)
at tickRootContext (core.js:8701:9)
at detectChangesInRootView (core.js:8726:5)
at RootViewRef.detectChanges (core.js:9991:9)
问题分析
上述调用上下文里,有一个栈帧是我们应用程序的代码:
ngAfterViewInit (ng-template.component.ts:20:20)
在其方法内设置断点, 发现运行时,this.tplRef 为空。
在值为 undefined 的变量上调用 createEmbeddedView
导致的这个错误。
问题转化为:this.tplRef
的赋值逻辑是怎样的?
在 ngOnInit 时,这个属性还是 undefined 状态:
我们把鼠标 hover 在 @ViewChild
上查看其说明:
变更检测器会在视图的 DOM 中查找能匹配上该选择器的第一个元素或指令。 如果视图的 DOM 发生了变化,出现了匹配该选择器的新的子节点,该属性就会被更新。
发现输入参数是一个选择器,本例我传入的选择器是 id 选择器:tpl
根据 Angular 官网文档,这意味着我的 HTML 模板文件里,tpl 之前应该用 #
修饰:
解决方案
在 tpl 前添加 #
:
总结
如果我们想进一步观察 view query 是如何根据传入的选择器 tpl
,去 dom tree 里查找的节点,可以添加如下代码,即 @ViewChild 和 set 函数搭配使用的情况。
@ViewChild('tpl')set thisNamedoesnotMatter(v:TemplateRef<any>){console.log('Jerry');this.tplRef = v;}
通过调试,发现 view query 的执行过程不会显示在 Chrome 开发者工具里,而仅仅显示一个 dummy 的 XXX(Component 名称)_Query 的调用上下文。
set 函数里的输入参数 v 代表的就是 id 为 tpl 的 Template 实例。
动态创建 @ViewChild 导致运行时错误的原因分析相关推荐
- Oracle显示表裂开,【案例】Oracle RAC脑裂导致节点重启原因分析
天萃荷净 Oracle研究中心案例分析:运维DBA反映Oracle RAC重启,分析原因为脑裂导致,结合日志分析产生原因. 本站文章除注明转载外,均为本站原创: 转载自love wife & ...
- udf mysql 重启_lib_mysqludf_json导致mysql重启原因分析
在<mysqludf_json将关系数据以JSON编码>提到使用lib_mysqludf_json会引起数据库重启.mysql错误日志如下: mysqld_safe Number of p ...
- 项目疑难杂症记录(四):Activity被重新创建的原因分析
在项目中遇到一个奇怪的Bug,插上带有升级包固件的U盘,选择升级框中的放弃按钮,Activity被onDestroy,随后又重新onCreate,相应的图片和日志如下: [一] 现象和日志 1.升级框 ...
- ShellExecuteEX打开iqy文件导致excel hang的原因分析
1. 问题 当在console中调用API ShellExecuteEx打开"test.iqy"文件时,发现excel会hang住,console退出后excel才会响应,但直接双 ...
- 虚拟服务器蓝屏,【原创】在虚拟机中运行系统导致实机系统蓝屏“0x000000F4”原因分析。...
本帖最后由 羊羔助手 于 2020-3-26 16:48 编辑 在虚拟机中运行系统导致实机系统蓝屏"0x000000F4"原因分析. 通常虚拟机中的系统是与实机的系统没有任何关联的 ...
- Microsoft JScript 运行时错误: 缺少对象,原因分析
今天接到一个任务,原因是一个不知道的jsp页面,在点击关闭一个div面板时发生错误: Microsoft JScript 运行时错误: 缺少对象,原因分析 然后百度了一番, 是某处的JavaScri ...
- SAP MM ME21N 创建PO时报错 - Net price in CNY becomes too large – 之原因分析
SAP MM ME21N 创建PO时报错 - Net price in CNY becomes too large – 之原因分析 昨天笔者在微信公众号里发布了一篇文章<SAP MM ME21N ...
- oracle10g cssd日志,【案例】Oracle CSSD进程HANG导致RAC节点重启原因分析笔记
[案例]Oracle CSSD进程HANG导致RAC节点重启原因分析笔记 时间:2016-11-04 19:20 来源:Oracle研究中心 作者:HTZ 点击: 次 天萃荷净 Oracl ...
- python 动态_python实现动态创建类的方法分析
本文实例讲述了python实现动态创建类的方法.分享给大家供大家参考,具体如下: python作为动态语言,如何在运行时动态创建类呢(python Creating classes dynamical ...
最新文章
- AI教父Hinton胶囊模型又出新作——胶囊如何表示视觉层次结构
- Linux系统主要目录及作用
- nginx strip模块优化页面
- boost::log模块实现从设置文件初始化库的示例
- ae抠像插件_AE抠像背景残留去除
- XCTF_Web_新手练习区:disabled_button
- 国内最大.NET平台重金招募中 你竟然还不知道?
- java 怎么使用同名类_java两个不同名类 在里面建立两个同名的类 怎么破
- 一个关于从1到100的加法算法
- win11非活动窗口如何设置 Windows11设置非活动窗口的步骤方法
- c++ 数据类型转换: static_cast、dynamic_cast、reinterpret_cast和const_cast
- c++ 单引和双引的区别
- 分享视频分析软件常用的几个C++库
- 数字c语言代码大全,C语言代码大全
- 爬取网站小猪短租的少量信息及详细介绍 ,requests库,bs4库的使用
- 做知识付费,这十大知识付费平台一定要知道
- Android device owner简述
- 【juns项目】信用卡数据项目2-2:数据设计
- 基于proteus的计数器设计
- 路由器密码忘记了?三步帮你重置找回!