本文讨论问题的代码,位于 Github:https://github.com/wangzixi-diablo/ngDynamic

问题描述

我的 Component 代码如下图所示:

  1. 使用依赖注入,引入 ViewContainerRef,从而可以使用其 createEmbeddedView 方法,在运行时动态创建实例。

  2. 使用 @ViewChild,获得该 Component HTML 源代码里定义的 id 为 tpl 的模板实例,类型为 TemplateRef

  3. 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 导致运行时错误的原因分析相关推荐

  1. Oracle显示表裂开,【案例】Oracle RAC脑裂导致节点重启原因分析

    天萃荷净 Oracle研究中心案例分析:运维DBA反映Oracle RAC重启,分析原因为脑裂导致,结合日志分析产生原因. 本站文章除注明转载外,均为本站原创: 转载自love wife & ...

  2. udf mysql 重启_lib_mysqludf_json导致mysql重启原因分析

    在<mysqludf_json将关系数据以JSON编码>提到使用lib_mysqludf_json会引起数据库重启.mysql错误日志如下: mysqld_safe Number of p ...

  3. 项目疑难杂症记录(四):Activity被重新创建的原因分析

    在项目中遇到一个奇怪的Bug,插上带有升级包固件的U盘,选择升级框中的放弃按钮,Activity被onDestroy,随后又重新onCreate,相应的图片和日志如下: [一] 现象和日志 1.升级框 ...

  4. ShellExecuteEX打开iqy文件导致excel hang的原因分析

    1. 问题 当在console中调用API ShellExecuteEx打开"test.iqy"文件时,发现excel会hang住,console退出后excel才会响应,但直接双 ...

  5. 虚拟服务器蓝屏,【原创】在虚拟机中运行系统导致实机系统蓝屏“0x000000F4”原因分析。...

    本帖最后由 羊羔助手 于 2020-3-26 16:48 编辑 在虚拟机中运行系统导致实机系统蓝屏"0x000000F4"原因分析. 通常虚拟机中的系统是与实机的系统没有任何关联的 ...

  6. Microsoft JScript 运行时错误: 缺少对象,原因分析

    今天接到一个任务,原因是一个不知道的jsp页面,在点击关闭一个div面板时发生错误: Microsoft JScript 运行时错误: 缺少对象,原因分析 然后百度了一番,  是某处的JavaScri ...

  7. 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 ...

  8. oracle10g cssd日志,【案例】Oracle CSSD进程HANG导致RAC节点重启原因分析笔记

    [案例]Oracle CSSD进程HANG导致RAC节点重启原因分析笔记 时间:2016-11-04 19:20   来源:Oracle研究中心   作者:HTZ   点击: 次 天萃荷净 Oracl ...

  9. python 动态_python实现动态创建类的方法分析

    本文实例讲述了python实现动态创建类的方法.分享给大家供大家参考,具体如下: python作为动态语言,如何在运行时动态创建类呢(python Creating classes dynamical ...

最新文章

  1. AI教父Hinton胶囊模型又出新作——胶囊如何表示视觉层次结构
  2. Linux系统主要目录及作用
  3. nginx strip模块优化页面
  4. boost::log模块实现从设置文件初始化库的示例
  5. ae抠像插件_AE抠像背景残留去除
  6. XCTF_Web_新手练习区:disabled_button
  7. 国内最大.NET平台重金招募中 你竟然还不知道?
  8. java 怎么使用同名类_java两个不同名类 在里面建立两个同名的类 怎么破
  9. 一个关于从1到100的加法算法
  10. win11非活动窗口如何设置 Windows11设置非活动窗口的步骤方法
  11. c++ 数据类型转换: static_cast、dynamic_cast、reinterpret_cast和const_cast
  12. c++ 单引和双引的区别
  13. 分享视频分析软件常用的几个C++库
  14. 数字c语言代码大全,C语言代码大全
  15. 爬取网站小猪短租的少量信息及详细介绍 ,requests库,bs4库的使用
  16. 做知识付费,这十大知识付费平台一定要知道
  17. Android device owner简述
  18. 【juns项目】信用卡数据项目2-2:数据设计
  19. 基于proteus的计数器设计
  20. 路由器密码忘记了?三步帮你重置找回!

热门文章

  1. php数组逗号连接,php – 如何使用逗号组合数组中的所有元素?
  2. less命令的使用方法
  3. BZOJ2240 : ural1676 Mortal Combat
  4. hadoop common 与 servlet 3冲突
  5. 用Shell脚本在推出的RAC节点上批量部署32个Oracle11gR2 RAC备份恢复案例场景的方法PART2...
  6. DIV+CSS布局参考站点
  7. 财务一体化项目,进度与计划11
  8. window 下内存泄漏检测
  9. Internet 网络协议族
  10. 快速傅里叶变换(FFT)相关内容汇总