Mat-Tree动态加载子节点后无法显示的问题排查
Mat-Tree动态加载子节点后无法显示的问题排查
我看了你贴的代码,遇到的问题是很典型的Angular Material Tree动态加载子节点时的变更检测和节点引用问题——明明dataSource.data里已经有子节点数据了,树却不渲染,别急,咱们一步步拆解问题、解决它。
先揪出代码里的核心问题
1. 没必要的节点查找,还搞错了引用
你在loadChildren里写了findNodeById去查找节点,但其实传入的node参数就是树里当前的那个节点实例!因为是引用类型,直接修改它的children属性就行,完全不用再去数组里找一遍,这不仅多此一举,还容易因为类型或引用的问题导致更新失效。
2. 类型混淆导致的隐性错误
你的treeControl是针对EsrsTreeNode类型的,但loadChildren的参数写的是EsrsNode,两者类型不匹配会让属性访问、变更检测都出隐性问题。
3. 变更检测触发的顺序不对
虽然你最后用了dataSource.data = dataSource.data.slice()来触发引用变化,但前面的节点更新方式不对,导致树控件没感知到子节点的变化。
针对性的修复方案
第一步:修正loadChildren的类型和逻辑
把参数类型改成EsrsTreeNode,直接修改传入的节点,省略多余的查找步骤:
loadChildren(node: EsrsTreeNode) { // 避免重复加载 if (node.children?.length) return; const docId = this.activatedRoute.snapshot.paramMap.get('id'); this.esrsDocumentService.getSectionNodes(docId, node.id) .subscribe((sections: SectionNode[]) => { // 把SectionNode转成EsrsTreeNode类型,直接赋值给当前节点的children node.children = sections.map(section => ({ ...section, hasChild: false, children: [] } as EsrsTreeNode)); // 触发Angular变更检测:更新dataSource.data的引用 this.dataSource.data = [...this.dataSource.data]; // 同步树控件的节点数组,确保它能拿到最新数据 this.treeControl.dataNodes = this.dataSource.data; // 展开当前节点,直接显示加载好的子节点 this.treeControl.expand(node); }); }
第二步:修正初始化时的类型转换
在ngOnInit里初始化根节点时,明确类型断言,避免类型混淆:
ngOnInit(): void { const docId = this.activatedRoute.snapshot.paramMap.get('id'); this.esrsDocumentService.getEsrsNodes(docId).subscribe((nodes: EsrsNode[]) => { console.log("EsrsDocumentDetailComponent ngOnInit", nodes); this.dataSource.data = nodes.map(n => ({ ...n, hasChild: n.hasChild, children: [] } as EsrsTreeNode)); // 初始化时同步treeControl的dataNodes this.treeControl.dataNodes = this.dataSource.data; }); }
第三步:确保trackById的类型正确
把trackById的参数类型明确为EsrsTreeNode,让Angular的跟踪更准确:
trackById(index: number, node: EsrsTreeNode): string { return node.id; }
为什么这样改能解决问题?
- 直接修改节点引用:利用JS的引用类型特性,修改传入的
node的children,相当于直接修改了dataSource.data里的节点数据; - 正确触发变更检测:用
[...this.dataSource.data]生成新的数组引用,让Angular感知到数据源变化,从而更新树的渲染; - 同步树控件的节点数组:
treeControl.dataNodes是树控件用来遍历节点的核心数组,必须和dataSource.data保持同步; - 类型统一:全程用
EsrsTreeNode类型,避免类型不匹配导致的隐性错误。
按这个方案改完后,你再点击展开按钮,子节点应该就能正常显示了,同时pre标签里的 data 也会和树的渲染一致。
内容来源于stack exchange
相关产品推荐
相关产品推荐

