0

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?

2
  • They should be, since all data is sync'd from parent to child by default. This seems like another issue. Maybe since the 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? Commented Jun 20, 2016 at 20:32
  • Unfortunately no improvement using v-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 the node property for an edge inside the v-for is not reflecting that change and remains empty. Commented Jun 21, 2016 at 14:59

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.