I'm creating a form builder for the backend of my site. There's a bunch of buttons for various fields represented by vue dynamic components (input, textarea, radio, checkbox, etc...) and on submit I'm looping through all of the components and storing each field as the object in an array to post via axios. The problem is in my axios.post function on submit, do I seriously have to write out every col for the model in there like I'm doing below? I'm supposed to have up to 20 fields so this feels absurd but I don't know how to assign the specific object data otherwise since it's not coming from the form itself but being created before the post.
Schema:
form
id
created_at
updated_at
field_1_name
field_1_type
field_1_data <= _data is always the object i create from the component data
field_2_name
field_2_type
field_2_data
field_3_name
field_3_type
field_3_data
Vue JS:
function checkValue(value) {
return (value ? value : "x");
}
Vue.component('text-input', {
props: ['count'],
data: function() {
return {
type: 'text-input',
label: '',
description: '',
required: ''
}
},
template: `
<div class="card text-input">
<span class="delete-field" @click="$emit('delete-field')"><i class="pe-7s-close"></i></span>
<div class="content">
<div class="header">
<h5>Text Field</h5>
</div>
<div class="content">
<div class="form-group">
<label for="label">Field Label <span class="require">*</span></label>
<input type="text" class="form-control" name="label" v-model="label" />
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea type="text" class="form-control" name="description" v-model="description"></textarea>
<span class="text-danger"></span>
</div>
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" name="required" type="checkbox" value="required" v-model="required">
<span class="form-check-sign"></span>
Required
</label>
</div>
</div>
</div>
</div>
`
});
Vue.component('quiz-field', {
data: function() {
return {
type: 'quiz-field',
label: '',
description: '',
required: '',
answers: [
{value:''},
{value:''}
]
}
},
methods: {
addAnswer() {
this.answers.push({ value: '' });
},
removeAnswer() {
this.answers.splice(1, 1);
}
},
template: `
<div class="card quiz-field">
<span class="delete-field" @click="$emit('delete-field')"><i class="pe-7s-close"></i></span>
<div class="content">
<div class="header">
<h5>Quiz Field</h5>
</div>
<div class="content">
<div class="form-group">
<label for="label">Quiz Question <span class="require">*</span></label>
<input type="text" class="form-control" name="label" v-model="label" />
<span class="text-danger"></span>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea type="text" class="form-control" name="description" v-model="description"></textarea>
<span class="text-danger"></span>
</div>
<div class="card">
<div id="root" class="content input-adder">
<h6>Quiz Answers:</h6>
<div class="form-group" v-for="answer in answers">
<input type="text" class="form-control vcenter" v-model="answer.value"><!--
--><span class="is-correct vcenter" data-toggle="tooltip" data-placement="top" title="Mark as complete"><i class="pe-7s-check"></i></span>
</div>
<button class="btn btn-primary btn-sm" @click.prevent="addAnswer">Add Answer</button>
<button class="btn btn-danger btn-sm" @click.prevent="removeAnswer">Remove Answer</button>
</div>
</div>
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" name="required" type="checkbox" value="required" v-model="required">
<span class="form-check-sign"></span>
Required
</label>
</div>
</div>
</div>
</div>
`
});
new Vue({
el: '#app',
data: {
inputs: [],
title: '',
description: '',
type: 'before',
},
methods: {
addField(type) {
this.fieldCount += 1;
if ('text-input' == type) {
this.inputs.push({
index: 'test',
type: type,
label: '',
description: '',
required: ''
});
} else if ('quiz-field' == type) {
this.inputs.push({
type: type,
fieldLabel: '',
fieldDescription: '',
required: '',
answers: [
{value:''},
{value:''}
]
});
}
},
onDeleteField(index) {
this.inputs.splice(index, 1);
},
onSubmit() {
// Looping through form builder fields and building their data as an object
var fields = [];
this.$root.$children.forEach(function(element, index) {
var type = element.type;
if ('text-input' == type || 'text-area' == type) {
fields[index] = {
type: type,
label: checkValue(element.label),
description: checkValue(element.description),
required: checkValue(element.required)
}
} else
if ('quiz-field' == type) {
fields[index] = {
type: type,
label: checkValue(element.label),
description: checkValue(element.description),
required: checkValue(element.required),
answers: checkValue(element.answers)
}
}
});
// We can only store up to 05 fields as part of a survey
// Here we are x'ing out for fields unused
var fieldCount = fields.length;
for (var i = fieldCount; i<=19; i++) {
fields[i] = {
type: 'x',
label: 'x',
description: 'x',
required: 'x'
}
}
// This is where the stupidity starts
axios.post('/surveys', {
title: this.title,
description: this.description,
type: this.type,
field_1_name: fields[0]['label'],
field_1_type: fields[0]['type'],
field_1_data: JSON.stringify(fields[0]),
field_2_name: fields[1]['label'],
field_2_type: fields[1]['type'],
field_2_data: JSON.stringify(fields[1]),
field_3_name: fields[2]['label'],
field_3_type: fields[2]['type'],
field_3_data: JSON.stringify(fields[2]),
field_4_name: fields[3]['label'],
field_4_type: fields[3]['type'],
field_4_data: JSON.stringify(fields[3]),
field_5_name: fields[4]['label'],
field_5_type: fields[4]['type'],
field_5_data: JSON.stringify(fields[4]),
field_6_name: fields[5]['label'],
field_6_type: fields[5]['type'],
field_6_data: JSON.stringify(fields[5]),
});
}
}
});