I'm trying to visualize a tree structure in Vue.js.
A small tree looks like the following:
{
"label": "outlook",
"edges": {
"== sunny": {
"label": "== sunny",
"node": {
"label": "humidity",
"edges": {
"<= 82": {
"label": "<= 82",
"node": {
"label": true
}
},
"> 82": {
"label": "> 82",
"node": {
"label": false
}
}
}
}
}
}
}
This might not be the most intuitive data structure for a tree, but I ended up with this since I need to display the labels for both the nodes and the edges.
The JSON object is used as input for a Tree
component with the following template:
<template id="tree-template">
<div class="tree clearfix">
<node v-ref:node :node-data="treeData"></node>
</div>
</template>
The Node
component looks as follows:
<template id="node-template">
<div class="node">
<div class="node__children" v-if="hasChildren">
<div class="node__child" v-for="edge in nodeData.edges">
<node :node-data="edge.node"></node>
</div>
</div>
</div>
</template>
The problem now is that the child node
components do not reflect changes made to the edges
property of the JSON object from above. For visualization purposes, the object gets constructed step-by-step using the generator pattern. I.e., I first start off with something like this:
{
"label": "outlook",
"edges": {
"== sunny": {
"label": "== sunny",
"node": {}
}
}
}
Where the node
property of edge == sunny
is an empty object. In the next step, that node
gets created and is set in the tree data.
I know that changes to object properties are not watched by default, but should still trigger view updates when using Vue.js' $set()
method:
this.$set('treeData.edges["== sunny"].node', node);
However, this change is only reflected at the top level (i.e. in the tree
component), which I can see by outputting {{ treeData | json }}
. Also, in the node
component embedded in tree
, { nodeData | json }}
reflects this change. (I also tried this.$set('treeData', treeData)
after having manipulated treeData
, but without success).
But if I output {{ edge.node }}
in the v-for
directive inside the node
component, it remains the empty object set during the initialization (and therefore no subsequent nodes are rendered).
I also tried to define an own watcher for this both in the tree
and node
component, but to no avail:
// ...
watch: {
'nodeData': {
handler: function(val, oldVal) {
console.log('nodeData updated:');
console.log(val);
},
deep: true
}
}
Any idea how I can get the (recursive) node
component to be aware of the changes to treeData
/ nodeData
?
edges
value is an object not an array, you need to use the<div class="node__child" v-for="(key, edge) in nodeData.edges">
syntax? – Jeff Jun 20 at 20:32v-for="(key, edge) in nodeData.edges"
. It seems that the data updates are at least partially working, since I see the changes when outputting{{ nodeData | json }}
, it's just that thenode
property for an edge inside thev-for
is not reflecting that change and remains empty. – Kubin Jun 21 at 14:59