Angular三级嵌套对象渲染异常求助:第三层级内容重复
Angular三级嵌套下拉/树形结构第三层级重复问题排查
问题描述
在Angular中实现三级嵌套下拉/树形结构,API返回扁平的地区关联数据(通过parent字段关联层级),当前代码可正常渲染第一、第二层级,但第三层级内容出现重复。
API返回数据
{"data": [{"id": "1","name": "Metro Manila","parent": null},{"id": "101","name": "Manila","parent": "1"},{"id": "10101","name": "Malate","parent": "101"},{"id": "10102","name": "Ermita","parent": "101"},{"id": "10103","name": "Binondo","parent": "101"},{"id": "102","name": "Makati","parent": "1"},{"id": "10201","name": "Poblacion","parent": "102"},{"id": "10202","name": "Bel-Air","parent": "102"},{"id": "10203","name": "San Lorenzo","parent": "102"},{"id": "10204","name": "Urdaneta","parent": "102"},{"id": "103","name": "Marikina","parent": "1"},{"id": "10301","name": "Sto Nino","parent": "103"},{"id": "10302","name": "Malanday","parent": "103"},{"id": "10303","name": "Concepcion I","parent": "103"},{"id": "2","name": "CALABARZON","parent": null},{"id": "201","name": "Laguna","parent": "2"},{"id": "20101","name": "Calamba","parent": "201"},{"id": "20102","name": "Sta. Rosa","parent": "201"},{"id": "202","name": "Cavite","parent": "2"},{"id": "20201","name": "Kawit","parent": "202"},{"id": "203","name": "Batangas","parent": "2"},{"id": "20301","name": "Lipa","parent": "203"},{"id": "20302","name": "Tanauan","parent": "203"},{"id": "3","name": "Central Luzon","parent": null},{"id": "301","name": "Bulacan","parent": "3"},{"id": "302","name": "Nueva Ecija","parent": "3"},{"id": "303","name": "Tarlac","parent": "3"},{"id": "304","name": "Pampanga","parent": "3"}]}
现有实现代码
this.data = result.body.data; let parents = this.data.filter(x => x.parent == null); let child_id = []; let child_id2 = []; for (let i = 0; i < parents.length; i++) { let _myTreelist = new ParentData(); _myTreelist.data.parent = parents[i].name; child_id = this.data.filter(x => x.parent == parents[i].id); //get child-1 with id _myTreelist.data.child.child1 = child_id.map((item) => { return item.name }) for (let e = 0; e < child_id.length; e++) { //10 ids child_id2 = this.data.filter(a => a.parent === child_id[e].id); //get child-2 with id _myTreelist.data.child.child.child2 = child_id2.map((item) => { return item.name }) } this.parentList.push(_myTreelist); }
异常效果截图

问题原因分析
原代码的核心问题是三级子节点的赋值逻辑错误:
在遍历二级节点(child_id)时,每次都将当前二级节点的三级子节点赋值给同一个_myTreelist.data.child.child.child2变量,后面的赋值会完全覆盖前面的结果。最终所有二级节点对应的三级子节点都会变成最后一个二级节点的子节点,导致第三层级内容重复。
修复方案
需要将二级节点与对应的三级子节点一一关联,而非共用一个数组。可以通过构建父子映射表的方式,高效整理层级关系,避免重复遍历:
修改后的代码
this.data = result.body.data; // 构建父子映射表,key为parent值,value为对应子节点数组 const childrenMap = new Map<string, any[]>(); this.data.forEach(item => { const parentKey = item.parent ?? 'root'; // 处理parent为null的情况 if (!childrenMap.has(parentKey)) { childrenMap.set(parentKey, []); } childrenMap.get(parentKey).push(item); }); // 生成三级嵌套结构 this.parentList = childrenMap.get('root').map(parent => ({ data: { parent: parent.name, child: { child1: childrenMap.get(parent.id)?.map(child1 => ({ name: child1.name, // 给每个二级节点绑定自己的三级子节点 child2: childrenMap.get(child1.id)?.map(child2 => child2.name) || [] })) || [] } } }));
逻辑说明
- 构建父子映射表:一次性遍历所有数据,将每个节点按
parent值分组,后续可以快速查找任意节点的子节点,避免多次调用filter提升性能。 - 层级关联:在生成二级节点时,同时为每个二级节点绑定对应的三级子节点,确保每个二级节点的三级内容都是自己的子节点,不会出现覆盖和重复。
内容的提问来源于stack exchange,提问作者Milestone89
相关产品推荐
相关产品推荐

