[英]How to create hierarchical HTML structure from flat JavaScript array?
I have been asked to create a stock list using a hierarchal system with parent ID's. 我被要求使用带有父ID的层次系统创建一个库存清单。 I'm having trouble displaying children under their parents.
我在带孩子到父母下时遇到麻烦。 I know I need to use a recursive function of some kind but my brain just won't let me work out how it would go together to accommodate for infinite amounts of indenting.
我知道我需要使用某种递归函数,但我的大脑不会让我知道如何将其结合起来以适应无限量的缩进。
Example JavaScript data... 示例JavaScript数据...
[
{id: 1, parent_id: null, title: "Row 1"},
{id: 2, parent_id: 1, title: "Row 2"},
{id: 3, parent_id: 2, title: "Row 3"},
{id: 4, parent_id: 2, title: "Row 4"}
]
Which the HTML should to look like... HTML应该是什么样的...
If anyone could help me it would be awesome as I've been stuck on this for almost 4 hours and I can't find anything that is relevant to my specific goal. 如果有人可以帮助我,那将是非常棒的事情,因为我已经坚持了将近4个小时,而我找不到与我的特定目标相关的任何东西。
Heads up : This requires your data to be ordered in a way that parent nodes appear before children reference them.
注意 :这要求您的数据必须按照父节点出现在子节点引用它们之前的顺序进行排序。 A
sort
could be done first, if required.如果需要,可以先进行
sort
。Edit : a no-sort solution is posted below
编辑 :排序解决方案发布在下面
Here's a way to do it using Array.prototype.reduce . 这是使用Array.prototype.reduce的一种方法。
var arr = [
{id: 1, parent_id: null, title: "Row 1"},
{id: 2, parent_id: 1, title: "Row 2"},
{id: 3, parent_id: 2, title: "Row 3"},
{id: 4, parent_id: 2, title: "Row 4"}
];
var x = arr.reduce(function(map, node) {
map.i[node.id] = node;
node.children = [];
node.parent_id === null ?
map.result.push(node) :
map.i[node.parent_id].children.push(node);
return map;
}, {i:{}, result:[]}).result;
Explanation. 说明。 I'll step through the reduce process I used
我将逐步完成所用的减少过程
initialize the reduce with {i:{}, result:[]}
使用
{i:{}, result:[]}
初始化 reduce {i:{}, result:[]}
We'll use the i
object as a means of referencing parent nodes and the result
array to store top-level root nodes 我们将使用
i
对象作为引用父节点和result
数组的方法,以存储顶级根节点
index each node by id
using map.i[node.id] = node
使用
map.i[node.id] = node
按id
索引每个map.i[node.id] = node
If the node is a root node ( parent_id === null
), add it to the result with map.result.push(node)
如果该节点是根节点 (
parent_id === null
),则使用map.result.push(node)
将其添加到结果中
If the node is a child node ( parent_id !== null
), add it to the children array of the parent node with map.index[node.parent_id].children.push(node)
如果该节点是子节点 (
parent_id !== null
),则使用map.index[node.parent_id].children.push(node)
将其添加到父节点的子节点数组中。
Okay, let's check if it worked 好吧,让我们检查一下是否可行
// all root nodes
// see output below
console.log(JSON.stringify(x, null, " "));
// first "root" node
console.log(x[0].id); //=> 1
// first child of first root node
console.log(x[0].children[0].id); //=> 2
// first child of first child of first root node
console.log(x[0].children[0].children[0].id); //=> 3
// second child of first child of first root node
console.log(x[0].children[0].children[1].id); //=> 4
All root nodes output 所有根节点输出
[
{
"id": 1,
"parent_id": null,
"title": "Row 1",
"children": [
{
"id": 2,
"parent_id": 1,
"title": "Row 2",
"children": [
{
"id": 3,
"parent_id": 2,
"title": "Row 3",
"children": []
},
{
"id": 4,
"parent_id": 2,
"title": "Row 4",
"children": []
}
]
}
]
}
]
If your initial data is unsorted ...
如果您的初始数据未排序 ...
The reduce
method is a little more difficult in this case. 在这种情况下,
reduce
方法要困难一些。 Admittedly, pretty much all elegance is lost with this solution, but I've provided it to show it's still possible. 诚然,此解决方案几乎失去了所有的优雅,但是我提供了它来证明它仍然可行。
// this works on arbitrarily sorted data
var x = arr.reduce(function(map, node) {
map.i[node.id] = node;
node.children = [];
if (node.parent_id === null) {
map.result.push(node);
}
else if (node.parent_id in map.i) {
map.i[node.parent_id].children.push(node);
}
else {
(node.parent_id in map.cache) ?
map.cache[node.parent_id].push(node) :
map.cache[node.parent_id] = [node];
}
if (node.id in map.cache) {
node.children = node.children.concat(map.cache[node.id]);
delete map.cache[node.id];
}
return map;
}, {i:{}, cache:{}, result:[]}).result;
You use an object that keeps track of your id's. 您使用一个跟踪ID的对象。 For example:
例如:
var idObj = {};
var root = null;
// first populate the object with elements
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
idObj[item.id] = item;
}
// then attach the children to the parents
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
var parent = idObj[item.parent_id];
if (parent) {
parent.children = parent.children || [];
parent.children.push(item);
} else if (item.parent_id === null) {
//set the item as root if it has no parents
root = item;
}
}
This will add a children
property to all those items. 这将为所有这些项目添加一个
children
属性。
Note: this solution is not recursive, but you can traverse the tree recursively starting from the root
variable. 注意:此解决方案不是递归的,但是您可以从
root
变量开始递归地遍历树。
Inspired by Naomik, the code will fail when the parent_id
s aren't in the correct position. 受Naomik的启发,当
parent_id
不在正确位置时,代码将失败。 Added a sorting function that will set them in the correct order. 添加了排序功能,可以按正确的顺序设置它们。
obj = [ {id: 2, parent_id: 1, title: "Row 2"}, {id: 3, parent_id: 2, title: "Row 3"}, {id: 4, parent_id: 2, title: "Row 4"}, {id: 1, parent_id: null, title: "Row 1"} ] obj.sort(function(a, b){ return (a.parent_id == null ? 0 : a.parent_id) - (b.parent_id == null ? 0 : b.parent_id); }); var tree = document.getElementById("tree"); for (var i = 0; i < obj.length; ++i) { if (obj[i].parent_id == null) { createTreeElement("li", obj[i].id, obj[i].title, tree); } else { var treeChildNode = document.getElementById("t" + obj[i].parent_id).getElementsByTagName("ul"); if (treeChildNode.length) { createTreeElement("li", obj[i].id, obj[i].title, treeChildNode[0]); } else { createTreeElement("ul", obj[i].parentId, "", document.getElementById("t" + obj[i].parent_id)); createTreeElement("li", obj[i].id, obj[i].title, document.getElementById("t" + obj[i].parent_id).getElementsByTagName("ul")[0]); } } } function createTreeElement(name, id, text, parent) { var node = document.createElement(name); node.id = "t" + id; node.innerHTML = text; parent.appendChild(node); }
<ul id="tree"> </ul>
This code is just a prove of concept in HTML to @Daniel Weiners answer why recursion isn't needed here based upon the object model. 这段代码只是@Daniel Weiners回答HTML的概念验证,为什么这里不需要基于对象模型进行递归。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.