I'm struggling to fully understand recursive components, but I believe they are the best approach for what I'm trying to achieve. Here is a Fiddle showing my progress so far:
My goal is to traverse through a nested JSON structure that simulates a DOM. Each "node" has properties like this:
"tagName": "section",
"classes": ["container", "mx-auto"],
"attrs": {"id":"main"},
"textNode": "",
"children": [{}]
Currently, I can recursively create each node as a component and store them in an array within the Vue Instance. However, I'm facing an issue where the child components need to be displayed inside their parent component. I'm considering creating an object with component objects and using a recursive component to parse them, but I'm unsure how to proceed.
Another idea is to create a flat array of components with parent IDs, and then somehow utilize this data structure?
I would appreciate guidance on how to tackle this challenge. I believe a recursive component will be beneficial, but I'm not sure how to integrate it with Create Element/Render Functions. Each node should have two-way binding with class lists, attribute lists, etc., which I plan to manage using states/stores or possibly Vuex.
The current code in the Fiddle displays all components from the JSON structure one after another without nesting.
const jsonData = [
{
"tagName": "section",
"classes": ["container","mx-auto"],
"attrs": {},
"textNode": "",
"children": [
{
"tagName": "div",
"classes": ["flex","flex-wrap"],
"attrs": {},
"textNode": "",
"children": [
{
"tagName": "div",
"classes": ["w-1/2"],
"attrs": {},
"textNode": "Hello"
},
{
"tagName": "div",
"classes": ["w-1/2"],
"attrs": {},
"textNode": "Goodbye"
}
]
}
]
}
];
let Components = [];
let uuid = 0;
function recurse() {
recursiveInitialize(jsonData)
}
function recursiveInitialize(j) {
if (Array.isArray(j)) {
return j.map((child) => recursiveInitialize(child))
}
if (j.children && j.children.length > 0) {
initializeComponent(j)
console.log("Hi I am " + j["tagName"] + " and a parent")
j.children.forEach((c) => {
console.log("Hi I am " + c["tagName"] + " and my parent is " + j["tagName"])
recursiveInitialize(c)
});
}
else {
console.log("Hi, I dont have any kids, I am " + j["tagName"])
initializeComponent(j)
}
}
function initializeComponent(jsonBlock){
let tempComponent = {
name: jsonBlock["tagName"]+ uuid.toString(),
methods: {
greet() {
store.setMessageAction(this)
}
},
data: function() {
return {
tagName: jsonBlock["tagName"],
classes: jsonBlock["classes"],
attrs: jsonBlock["attrs"],
children: jsonBlock["children"],
textNode: jsonBlock["textNode"],
on: {click: this.greet},
ref: uuid,
}
},
beforeCreate() {
this.uuid = uuid.toString();
uuid += 1;
},
render: function(createElement) {
return createElement(this.tagName, {
class: this.classes,
on: {
click: this.greet
},
attrs: this.attrs,
}, this.textNode);
},
mounted() {
// example usage
console.log('This ID:', this.uuid);
},
}
Components.push(tempComponent);
return tempComponent
}
const App = new Vue({
el: '#app',
data: {
children: [
Components
],
},
beforeCreate() {
recurse();
console.log("recurseRan")
},
mounted() {
this.populate()
},
methods: {
populate() {
let i = 0;
let numberOfItems = Components.length;
for (i = 0; i < numberOfItems; i++) {
console.log("populate: " + Components[i])
this.children.push(Components[i]);
}
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template v-for="(child, index) in children">
<component :is="child" :key="child.name"></component>
</template>
</div>