How to load the form elements and its attribute dynamically - vue.js

I want to load the template and its form elements dynamically.
The desired output:
I want to load all these fields dynamically so that form should be generic and I can use the same template for all forms in my project.
The code I have tried:
<template>
<b-card>
<b-row>
<b-col sm="3">
<b-form-group>
<label v-for="option in labelNames">{{ option.name }}</label>
<input :type="text" :id="name" :class="form-control" :placeholder="Enter your name" :v-validate="'required|Name'" :name="Firstname" v-model="firstName">
<span v-show="errors.has(':name')" class="is-danger">{{ errors.first(':name') }}</span>
</b-form-group>
</b-col>
</b-row>
</b-card>
</template>
<script>
export default {
name: 'addEmpl',
data () {
return {
labelNames: [
{ name: 'FirstName'},
{ name: 'LastName'},
{ name: 'MiddleName'},
{ name: 'EmployeeID'},
{ name: 'Gender'},
],
inputs: [
{ type: 'text', id : 'name1', class : 'form-control' placeholder : 'Enter your name' name: 'Firstname' v-validate : 'required'},
{ type: 'text', id : 'name2', class : 'form-control' placeholder : 'Enter your middle name' name: 'Middlename' v-validate : 'required'},
{ type: 'text', id : 'name3', class : 'form-control' placeholder : 'Enter your last name' name: 'Lastname' v-validate : 'required'},
],
}
}
}
</script>
Kindly suggest me a better option to do generic forms. Thanks in advance

Related

Dynamically create v-model from form input field in VueJS

I want to create a form dynamically from a json response obtained from backend.
Here is the code:
<template>
<div class="container">
<div v-for="field in form">
<div v-if="field.type === 'text'">
<input type="text" :name="field.name" :placeholder="field.label"/>
</div>
<div v-else-if="field.type === 'radio'">
<div v-for="option in field.options">
<label>
<input type="radio" :name="field.name" :value="option">
<span class="text">{{ option }}</span>
</label>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
form: [
{
name: 'first_name',
label: 'First Name',
type: 'text',
},
{
name: 'last_name',
label: 'Last Name',
type: 'text',
},
{
name: 'gender',
label: 'Gender',
type: 'radio',
options: ['male','female'],
}
],
response: [], <!--I want to populate this array with form response.-->
}
}
}
</script>
Now, I don't know how many fields to be created and don't know the name. I get a different response from each different request. So I need a way to fill the response[] array with form data. The response[] array may look like this:
response: [
{
name: 'first_name',
value: 'Yeasir',
},
{
name: 'last_name',
value: 'Arafat',
},
{
name: 'gender',
value: 'male',
}
]
How can I achieve the result? It would be a great help.

How to make this drop down change the value after selecting another option in Vue.js?

We are trying to select another item from drop down options but it doesn't changing the value:
<b-dropdown aria-role="list">
<b-button
icon-right="caret-down"
class="dropdown"
size="is-small"
slot="trigger"
>
<span>{{selectedProduct}}</span>
</b-button>
<b-dropdown-item
v-for="product in products"
:key="product.id"
aria-role="listitem"
#click="setItem(selectedProduct)"
v-model="selectedProductTag"
>
{{ product.name }}
</b-dropdown-item>
</b-dropdown>
**js part**
editProduct(){
...
...
this.selectedProductTag = {
id: selectedProductId,
name: product.name,
tag: product.tag,
};
}
setItem(selectedProduct) {
this.selectedProduct = selectedProduct
},
How to make it change both the selected option labels as well as v-model object data?
I see you're using a bootstrap-vue component, but, for what you're doing, I would suggest you to use the select component instead. But anyways, using the dropdown component:
In your HTML
<b-dropdown aria-role="list" v-bind:text="(selectedProduct.id == 0? 'Select here' : selectedProduct.name)">
<b-dropdown-item
v-for="(product, index) in products"
:key="index"
aria-role="listitem"
#click="setItem(product)"
>{{ product.name }}</b-dropdown-item>
</b-dropdown>
In your data section
data() {
products: [
{
id: 1,
name: "test1",
value: 1,
etc: "..."
},
{
id: 2,
name: "test2",
value: 2,
etc: "..."
}
//....
],
selectedProduct: {
id: 0,
name: "",
value: 0,
etc: "..."
}
//Make sure not to set selectedProduct to `null`, as it could result on an error
}
In your methods section
setItem: function(product) {
this.selectedProduct = product;
},

"prop" is undefined though it's being passed correctly

I've been following VueJS official documentation on passing data to child components with props; though I'm not working with a string template. I'm aware about what happens when your prop is camel case; you should write it as kebab case.
Nevertheless, this is not the case since it's all lowercase and won't work.
I'm using nuxt and I've separated my work into files, which are:
<template>
<div class="row">
<input type="text" name="" id="" placeholder="Write your question" v-model="text">
<select v-model="selectedField">
<option v-for="option in options" :key="option.id" :value="option.value">
{{ option.text }}
</option>
</select>
<button class="btn btn-sm btn-primary" #click="$emit('add-field')"
v-bind:class="{ disabled: ($parent.count <= 1 && $parent.count == identifier) }">
>{{identifier}}</button>
<button class="btn btn-sm btn-danger" #click="$emit('delete-field')">-</button>
</div>
Now for its JS file:
export default {
data () {
return {
options: [
{
id: 1,
value: 1,
text: "Radio"
},
{
id: 2,
value: 2,
text: "Rate"
},
{
id: 3,
value: 3,
text: "Text"
}
],
props: ['identifier'],
selectedField: 1,
text: "",
}
},
}
Now, for my parent component:
<template>
<div class="offset-md-3" id="qz">
<form-maker
v-for="item in questions" :key="item._id"
v-on:add-field="addField()"
v-on:delete-field="deleteField(item._id)"
v-bind:identifier="item._id" <<--What I want to set
ref="child"
></form-maker>
<button #click="saveForm" class="btn btn-large btn-success">SAVE</button>
</div>
</template>
Finally:
var vm = null;
export default {
layout: 'admin',
components: {
formMaker
},
data() {
return {
count: 1,
questions: [{
_id: 1//static
}]
}
},
}
What I'm trying to do is, to use the prop for some validations, nevertheless it throws the next error:
Property or method "identifier" is not defined on the instance but
referenced during render. Make sure that this property is reactive,
either in the data option, or for class-based components, by
initializing the property.
Thank you.
Here is where you go wrong. Props should not be in data(). See the code snippet below
<script>
export default {
props: ['identifier'],
data() {
return {
options: [
{
id: 1,
value: 1,
text: "Radio"
},
{
id: 2,
value: 2,
text: "Rate"
},
{
id: 3,
value: 3,
text: "Text"
}
],
selectedField: 1,
text: "",
}
}
}
</script>

When I use dynamic variables for my v-model it doesn't work

So, I have a simple form:
<template v-for="form in forms">
{{ form.header }}
<template v-for="input in form.inputs">
<label>{{ input.label }}</label>
<v-flex class="xs12 md6">
<input :v-model="input.key" />
</v-flex>
</template>
</template>
Which is being dynamically made from a forms data object:
forms:[
{
header: 'General Information',
description: 'General Information',
inputs: [
{
label: 'First name',
key: 'account.firstname'
},
]
}
I have a pre-build account object for the v-model:
data: () => ({
account: {
firstname: 'Initial firstname'
}
})
But this is not working. I get no errors, but my dynamic v-model is not getting the account.firstname data. What am I missing to fix this?

Vue.js nested for loop input field model binding

In this example I am allowing the user to create their own typed list of sections. Each type has it's own form fields. The form fields render properly however, if I enter data into one of the fields after I've created two duplicate sections, both inputs are updated with the typed in text. This is not the intended result.
Instead each section should update its form field data content individually and it should reflect back to the value stored within the data.section related to it.
What am I missing?
Laravel View
{{Form::open(['route' => 'api.post.store', 'class' => 'form-horizontal'])}}
<fieldset>
<div id="legend">
<legend class="">Register</legend>
</div>
<div :key="section.id" v-for="(index,section) in sections" class="control-group form-group-lg">
<div class="form-header">
<h3>#{{ section.label }}</h3>
</div>
<pre>#{{ section | json }}</pre>
<div v-for="field in section.fields" :key="field.id">
<div class="text-field" v-show="field.inputType == 'text'">
<label class="control-label" :for="section.name">#{{ field.label }}</label>
<div class="controls">
<input v-model="field.data.content" class="input-xlarge form-control">
<p class="help-block">#{{ field.helpText }}</p>
</div>
</div>
<div class="text-area-field" v-show="field.inputType == 'text-area'">
<label class="control-label" :for="section.name">#{{ field.label }}</label>
<div class="controls">
<textarea :v-bind="field.data.content" class="input xlarge form-control" :placeholder="field.placeholder">
#{{ field.data.content }}
</textarea>
</div>
</div>
<div class="text-area-field" v-show="field.inputType == 'data-map'">
<label class="control-label" :for="section.name">#{{ field.label }}</label>
<div class="controls">
<textarea :v-bind="field.data.content" class="input xlarge form-control" :placeholder="field.placeholder">
#{{ field.data.content }}
</textarea>
</div>
</div>
</div>
</div>
<div class="control-group">
<div class="controls">
<div class="dropdown">
<a data-target="#" href="page.html" data-toggle="dropdown" class="dropdown-toggle">Dropdown <b class="caret"></b></a>
<ul class="dropdown-menu">
<li v-for="sectionType in sectionTypes">
<a #click="setSectionCreateType(sectionType)" href="#">#{{ sectionType.label }}</a>
</li>
</ul>
</div>
</div>
<div class="controls">
<div #click="addSection()" class="btn bdn-success" class="btn btn-success">Add Section</div>
<div #click="savePost()" class="btn bdn-success" class="btn btn-success">Save</div>
</div>
</div>
</fieldset>
{{Form::close()}}
Vuefile
<script type="text/javascript">
import Vue from 'vue';
import FormField from './create/FormField.vue';
export default {
components: {
FormField,
},
ready: function () {
},
filters: {},
data(){
return {
messages: [],
sections: [],
saveSections: [],
sectionCreateType: false,
sectionTypes: [
{
label: 'Company',
map: 'company',
fields: [
{
label: 'name',
name: 'name',
inputType: 'text',
placeholder: 'Company Name',
data: {
content: '',
},
},
{
label: 'symbol',
name: 'symbol',
inputType: 'text',
placeholder: 'stock symbol',
data: {
content: '',
},
}
]
},
{
label: 'Link',
map: 'link',
inputType: 'text',
data: {},
fields: [
{
label: 'url',
name: 'url',
inputType: 'text',
placeholder: 'Url',
data: {
content: '',
},
},
]
},
{
label: 'Paragraph',
map: 'paragraph',
data: {},
fields: [
{
label: 'content',
name: 'content',
inputType: 'text-area',
placeholder: 'Content',
data: {
content: '',
},
},
]
},
{
label: 'Person',
map: 'person',
data: {},
inputType: 'data-map',
'fields': [
{
label: 'first_name',
name: 'name',
placeholder: 'Person Name',
data: {
content: '',
},
},
{
label: 'last_name',
name: 'name',
placeholder: 'Person Name',
data: {
content: '',
},
}
]
},
],
}
},
directives: {},
events: {},
methods: {
setSectionCreateType(type)
{
console.log('setting sectionCreateType: ' + type.label)
this.sectionCreateType = type;
},
addSection()
{
if (!this.sectionCreateType) {
this.sectionCreateType = this.sectionTypes[0];
}
this.createSection(this.sectionCreateType);
},
createSection(type)
{
this.sections.push(Vue.util.extend({}, type))
},
previewPost(){
},
savePost: function(){
var view = this;
var saveObject = [];
var sectionObject = [];
this.sections.forEach(function (section) {
if(!sectionObject[section.type.map])
{
sectionObject[section.type.map] = [];
}
for (var key in section.type.fields) {
var field = section.type.fields[key];
var saveKey = [];
saveKey[field.name] = field.data.content;
}
sectionObject[section.type.map].push(saveKey);
});
saveObject.push(sectionObject);
console.log(saveObject);
},
}
}
</script>
You are using the same v-model so VueJS does what it should do.
You have to create e.g. list of models and somehow handle index (e.g. take it from v-for for every section/subsection and use v-model='list[index].field