How do I display nested elements on the UI when dynamically generated based on a parent element's selected option (e.g. List)? For example, in the code below, when creating a field and selecting the List option, another nested should appear, and so on with an unknown depth. How can I render this for the user to see? Using v-for inside v-for doesn't seem to work. Do I need recursion here, but I'm unsure how to implement it.
Any help would be greatly appreciated!
var app = new Vue({
el: '.container',
data: {
modelname: '',
fields: []
},
methods: {
addNewField() {
this.fields.push({
left: 0,
type:'',
method:'',
size:'',
value:''}
)
},
createChildElement(field) {
if (field.type == "List") {
Vue.set(field, "value", []);
field.value.push({
type:'',
left: field.left+20,
method:'',
size:'',
value:''}
);
}
},
showJson() {
const data = this.fields
alert(JSON.stringify(data, null, 2));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container">
<h1 class="font-italic text-warning">TDGT Web Client</h1>
<div>
<button id="add-field" class="btn btn-sm btn-warning" @click="addNewField">Create field</button>
<button id="show-json" class="btn btn-sm btn-warning" @click="showJson">Show JSON</button>
<div v-for="(field, index) in fields" :style="{marginLeft: field.left+'px'}" :key="index">
<ul>
<li>
<select v-model="field.type" v-on:change="createChildElement(field)" aria-label="Choose field type">
<option selected>Field Type</option>
<option value="List">List</option>
<option value="Map">Map</option>
<option value="Integer">Integer</option>
</select>
<select v-model="field.method" v-if="field.type === 'Map' || field.type === 'List'" aria-label="Generation Method">
<option selected>Value Type</option>
<option value="Static">Static</option>
<option value="Random">Random</option>
<option value="Range">Range</option>
</select>
<input type="text" v-if="field.type === 'Map' || field.type === 'List'" v-model="field.size" placeholder="Dimension">
<input type="text" v-if="field.type === 'Integer'" v-model="field.value" placeholder="Value">
</li>
<ul></ul>
</ul>
</div>
</div>
</div>
UPD. Following the suggestions provided, I attempted to find a solution for my task, but encountered some issues that I am unable to resolve. Some errors include:
Invalid prop: type check failed for prop "item". Expected Object, got Array.
Property or method "fields" is not defined on the instance but referenced during render.
Here is the updated code:
Vue.component("el-inpt-group", {
template: "#item-template",
props: {
item: Object,
}
});
var app = new Vue({
el: '.container',
data: {
modelname: '',
fields: [
]
},
methods: {
addNewField() {
this.fields.push({
name: '',
left: 0,
type:'',
method:'',
size:'',
value:''}
)
},
createChildElement(field) {
if (field.type == "List") {
Vue.set(field, "value", []);
field.value.push({
name: '',
type:'',
left: field.left+20,
method:'',
size:'',
value:''}
)
}
},
showJson() {
const data = this.fields
alert(JSON.stringify(data, null, 2));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/x-template" id="item-template">
<ul>
<li v-for="field in fields">
<input type="text" v-model="field.name" placeholder="Name">
<select v-model="field.type" v-on:change="createChildElement(field)" aria-label="Choose field type">
<option selected>Field Type</option>
<option value="List">List</option>
<option value="Map">Map</option>
<option value="Integer">Integer</option>
</select>
<select v-model="field.method" v-if="field.type === 'Map' || field.type === 'List'" aria-label="Generation Method">
<option selected>Value Type</option>
<option value="Static">Static</option>
<option value="Random">Random</option>
<option value="Range">Range</option>
</select>
<input type="text" v-if="field.type === 'Map' || field.type === 'List'" v-model="field.size" placeholder="Dimension">
<input type="text" v-if="field.type === 'Integer'" v-model="field.value" placeholder="Value">
</li>
<ul><el-inpt-group v-for="child in fields.value" :style="{marginLeft: field.left+'px'}" :key="child.name" :item="child"></el-inpt-group></ul>
</ul>
</script>
</head>
<body>
<div class="container">
<h1 class="font-italic text-warning">TDGT Web Client</h1>
<button id="add-field" class="btn btn-sm btn-warning" @click="addNewField">Create Field</button>
<button id="show-json" class="btn btn-sm btn-warning" @click="showJson">Show JSON</button>
<el-inpt-group :item="fields"></el-inpt-group>
</div>
</div>