How to sort a list by item valie in VueJs? - vue.js

Is it possible in VueJs to display my blocks sorted by "block.position" value, and update all block position when I click on a "UP" or "DOWN" button?
I want to have my blocks in correct order in my "blocks" array, reflect the index position on the "block.position" value, and display all my blocks in a correct order.
<template>
<div>
<div class="mb-5" v-for="(block, index) in blocks" :key="block.id">
<div class="btn btn-primary" #click="move(index,index-1)" v-if="index">
<span class="fa fa-arrow-up"></span>
</div>
<div class="btn btn-primary"
#click="move(index,index+1)" v-if="index !== (blocks.length - 1)">
<span class="fa fa-arrow-down"></span>
</div>
<h3 class="text-uppercase text-info"><u>{{ block.name }}</u> - {{ block.position }}</h3>
<div v-for="field in block.fields" :key="field.id">
<p>{{ field.name }}</p>
<div class="mb-3">
<div v-if="field.type === 'textarea'">
<textarea
:required="field.required"
:placeholder="field.attr ? field.attr.placeholder : null"
:value="field.data"
/>
</div>
<div v-else>
<input
:type="field.type"
:required="field.required"
:placeholder="field.attr ? field.attr.placeholder : null"
:value="field.data"
/>
</div>
<div class="alert alert-danger" v-for="error in field.errors">
{{ error }}
</div>
</div>
</div>
<hr class="border-light">
</div>
<ul class="list-unstyled d-block">
<li class="d-inline-block">
<button class="btn btn-light" v-on:click="addParagraph">
Add Paragraph
</button>
</li>
<li class="d-inline-block ml-3">
<button class="btn btn-light" v-on:click="addImage">
Add Image
</button>
</li>
</ul>
</div>
</template>
<script>
// Going to use this neat array function
Array.prototype.move = function (from, to) {
this.splice(to, 0, this.splice(from, 1)[0]);
return this;
};
export default {
name: 'BlockForm',
created() {
// Tri dans le tableau les blocks par "block.position".
this.updateBlockPosition();
},
data() {
return {
blocks: [
{
id: 0,
type: 'paragraph',
name: 'Paragraphe',
position: '1',
fields: [
{
id: 0,
type: 'textarea',
name: 'Saisissez votre texte ci-dessous',
required: true,
data: null,
errors: [
'Lorem ipsum sir dolor emet',
],
},
],
},
{
id: 1,
type: 'image',
name: 'Image',
position: '2',
fields: [
{
id: 0,
type: 'file',
name: 'Sélectionner une image',
required: false,
placeholder: null,
data: null,
errors: [],
},
{
id: 1,
type: 'text',
name: 'Description de l\'image',
required: false,
placeholder: null,
data: null,
errors: [],
},
],
},
{
id: 2,
type: 'image',
name: 'Image',
position: '3',
fields: [
{
id: 0,
type: 'file',
name: 'Sélectionner une image',
required: false,
placeholder: null,
data: null,
errors: [],
},
{
id: 1,
type: 'text',
name: 'Description de l\'image',
required: false,
placeholder: null,
data: null,
errors: [],
},
],
},
],
};
},
methods: {
addParagraph() {
this.blocks.push({ ...this.blocks[0] });
this.updateBlockPosition();
},
addImage() {
this.blocks.push(this.blocks[1]);
this.updateBlockPosition();
},
move(from, to) {
this.blocks.move(from, to);
this.updateBlockPosition();
},
updateBlockPosition() {
this.blocks.forEach((block, index) => {
block.id = index + 1;
block.position = index + 1;
});
},
},
};
</script>

Related

How to remove html tags

Hi everyone I want to not show "html tags" When i have data in tables, but i want show text only like microsoft word, I'm not sure on the support, I don't know to fix it and I have tried many times, I think can't to remove all the html tags from string, I used CKeditor to input and datatable of vue output from vueX
help me please
Example Outpout
<template>
<div class="container" id="annoucements">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header card-header-primary card-header-icon">
<div class="card-icon">
<i class="material-icons">assignment</i>
</div>
<h4 class="card-title">
{{ $t('global.table') }}
<strong>{{ $t('cruds.annoucement.title') }}</strong>
</h4>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-12">
<div class="table-overlay" v-show="loading">
<div class="table-overlay-container">
<material-spinner></material-spinner>
<span>Loading...</span>
</div>
</div>
<datatable
:columns="columns"
:data="data"
:total="total"
:query="query"
:xprops="xprops"
:HeaderSettings="false"
:pageSizeOptions="[10, 25, 50, 100]"
>
<global-search :query="query" class="pull-left" />
<span style="margin-left:10%">
<button
type="button"
class="btn btn-default"
#click="fetchIndexData"
:disabled="loading"
:class="{ disabled: loading }"
>
<i class="material-icons" :class="{ 'fa-spin': loading }">
refresh
</i>
{{ $t('global.refresh') }}
</button>
</span>
<header-settings :columns="columns" class="pull-right" />
</datatable>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import TranslatedHeader from '#components/Datatables/TranslatedHeader'
import HeaderSettings from '#components/Datatables/HeaderSettings'
import GlobalSearch from '#components/Datatables/GlobalSearch'
import DatatableAttachments from '#components/Datatables/DatatableAttachments'
export default {
components: {
GlobalSearch,
HeaderSettings
},
data() {
return {
columns: [
{
title: 'cruds.annoucement.fields.id',
field: 'id',
thComp: TranslatedHeader,
sortable: true,
colStyle: 'width: 100px;'
},
{
title: 'cruds.annoucement.fields.annoucement',
field: 'annoucement',
thComp: TranslatedHeader,
tdComp: DatatableAttachments
},
{
title: 'cruds.annoucement.fields.name',
field: 'name',
thComp: TranslatedHeader,
sortable: true
},
{
title: 'cruds.annoucement.fields.number',
field: 'number',
thComp: TranslatedHeader,
sortable: true
},
{
title: 'cruds.annoucement.fields.short_name',
field: 'short_name',
thComp: TranslatedHeader,
sortable: true
},
{
title: 'cruds.annoucement.fields.allow_date',
field: 'allow_date',
thComp: TranslatedHeader,
sortable: true
},
{
title: 'cruds.annoucement.fields.description',
field: 'description',
thComp: TranslatedHeader,
}
],
query: { sort: 'id', order: 'desc', limit: 100, s: '' },
xprops: {
module: 'AnnoucementsIndex',
route: 'annoucements',
permission_prefix: 'annoucement_'
}
}
},
beforeDestroy() {
this.resetState()
},
computed: {
...mapGetters('AnnoucementsIndex', ['data', 'total', 'loading'])
},
watch: {
query: {
handler(query) {
this.setQuery(query)
this.fetchIndexData()
},
deep: true
}
},
methods: {
...mapActions('AnnoucementsIndex', [
'fetchIndexData',
'setQuery',
'resetState'
])
}
}
</script>
Use method below for each cell or make an copy of data that contains string without html:
removeHtmlTags(htmlString) {
const tmp = document.createElement('DIV');
tmp.innerHTML = htmlString;
return tmp.textContent || tmp.innerText || '';
}

v-show within a v-for loop - show only clicked option

I have a v-for loop set up there is a show button within the loop, when I click this, at the moment it opens all the hidden divs, I want it to open only the relevant one thats clicked. Maybe there is another way to do this or a better way I have been reading that v-show might net be suited to be used inside a loop.
<div id="app" class="container">
<form>
<div v-for="item in filterOptions" :class="{ activeclass: isActive }">
<dl>
<dt>
<!--- click to show --->
<button #click="toggle(item)" #click.self.prevent>{{item.name}}</button>
</dt>
<!--- show this --->
<dd v-show="isActive" :id="item.name">
<button v-for="option in item.values" v-on:click="option.selected = !option.selected" type="button" class="btn btn-primary" :class="{'active' : option.selected}">
{{option.name}}
</button>
</dd>
</dl>
</div>
</form>
<div v-for="item in products">
<div>
<h5>
{{item.name}}
</h5>
<h6>{{item.region}}</h6>
<a>View</a>
</div>
</div>
</div>
var main = new Vue({
el: '#app',
data: {
products: [
{
name: "davy",
region: "Highland",
category: "Single Cask"
},
{
name: "bill",
region: "Islay",
category: "New releases"
},
{
name: "shena",
region: "Highland",
category: "Remarkable Regional Malt"
}
],
filterOptions: [
{
name: 'Region',
isActive: false,
values: [
{
name: 'Highland',
selected : false
},
{
name: 'Speyside',
selected : false
},
{
name: 'Islay',
selected : false
}
]
},
{
name: 'Price',
isActive: false,
values: [
{
name: '£1-50',
selected : false
},
{
name: '£51-100',
selected : false
},
]
},
{
name: 'Category',
isActive: false,
values: [
{
name: 'Single Cask',
selected : false
},
{
name: 'Remarkable Regional Malt',
selected : false
},
{
name: 'New releases',
selected : false
}
]
}
],
isHidden: true,
isActive: false
},
methods: {
toggle: function () {
this.isActive = !this.isActive;
}
}
})
I hope this will help you
window.onload = function() {
new Vue({
el: '#app',
data: {
products: [
{
name: "davy",
region: "Highland",
category: "Single Cask"
},
{
name: "bill",
region: "Islay",
category: "New releases"
},
{
name: "shena",
region: "Highland",
category: "Remarkable Regional Malt"
}
],
filterOptions: [
{
name: 'Region',
isActive: false,
values: [
{
name: 'Highland',
selected : false
},
{
name: 'Speyside',
selected : false
},
{
name: 'Islay',
selected : false
}
]
},
{
name: 'Price',
isActive: false,
values: [
{
name: '£1-50',
selected : false
},
{
name: '£51-100',
selected : false
},
]
},
{
name: 'Category',
isActive: false,
values: [
{
name: 'Single Cask',
selected : false
},
{
name: 'Remarkable Regional Malt',
selected : false
},
{
name: 'New releases',
selected : false
}
]
}
],
isHidden: true,
isActive: false,
selectedName: ''
},
methods: {
toggle: function (item) {
this.selectedName = item.name
}
}
})
}
.success {
display: block !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='app'>
<div id="app" class="container">
<form>
<div v-for="item in filterOptions" :class="{ activeclass: isActive }">
<dl>
<dt>
<!--- click to show --->
<button v-on:click.prevent="toggle(item)">{{item.name}}</button>
</dt>
<!--- show this --->
<dd :id="item.name" v-if="item.name == selectedName" v-bind:class="{'success': (item.name == selectedName)}">
<button v-for="option in item.values" v-on:click="option.selected = !option.selected" type="button" class="btn btn-primary" :class="{'active' : option.selected}">
{{option.name}}
</button>
</dd>
</dl>
</div>
</form>
<div v-for="item in products">
<div>
<h5>
{{item.name}}
</h5>
<h6>{{item.region}}</h6>
<a>View</a>
</div>
</div>
</div>
</div>
Define activeitem in data and set this.activeitem = item.namein toggle method.
toggle: function (item) {
this.isActive = !this.isActive;
this.activeitem = item.name
}
in HTML add v-show="item.name == activeitem && isActive"
<dd v-show="item.name == activeitem && isActive" :id="item.name">
<button v-for="option in item.values" v-on:click="option.selected = !option.selected" type="button" class="btn btn-primary" :class="{'active' : option.selected}">
{{option.name}}
</button>
</dd>
var main = new Vue({
el: '#app',
data: {
activeitem:null,
products: [
{
name: "davy",
region: "Highland",
category: "Single Cask"
},
{
name: "bill",
region: "Islay",
category: "New releases"
},
{
name: "shena",
region: "Highland",
category: "Remarkable Regional Malt"
}
],
filterOptions: [
{
name: 'Region',
isActive: false,
values: [
{
name: 'Highland',
selected : false
},
{
name: 'Speyside',
selected : false
},
{
name: 'Islay',
selected : false
}
]
},
{
name: 'Price',
isActive: false,
values: [
{
name: '£1-50',
selected : false
},
{
name: '£51-100',
selected : false
},
]
},
{
name: 'Category',
isActive: false,
values: [
{
name: 'Single Cask',
selected : false
},
{
name: 'Remarkable Regional Malt',
selected : false
},
{
name: 'New releases',
selected : false
}
]
}
],
isHidden: true,
isActive: false
},
methods: {
toggle: function (item) {
this.isActive = !this.isActive;
this.activeitem = item.name
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app" class="container">
<form>
<div v-for="item in filterOptions" :class="{ activeclass: isActive }">
<dl>
<dt>
<!--- click to show --->
<button #click="toggle(item)" #click.self.prevent>{{item.name}}</button>
</dt>
<!--- show this --->
<dd v-show="item.name == activeitem && isActive" :id="item.name">
<button v-for="option in item.values" v-on:click="option.selected = !option.selected" type="button" class="btn btn-primary" :class="{'active' : option.selected}">
{{option.name}}
</button>
</dd>
</dl>
</div>
</form>
<div v-for="item in products">
<div>
<h5>
{{item.name}}
</h5>
<h6>{{item.region}}</h6>
<a>View</a>
</div>
</div>
</div>

How can I send formdata, objects, image?

Why can't I send these two form values? In my POST data I have regular form data, a photo, and two objects "cat" and "medication"...
my post method....
postCarelog(catID, catName) {
axios.post(`/api/v1/carelogs/`, {
cat: {id: catID, name: catName},
weight_unit_measure: 'G',
weight_before_food: this.weight_before_food,
food_unit_measure: 'G',
amount_of_food_taken: this.amount_of_food_taken,
food_type: this.food_type,
weight_after_food: this.weight_after_food,
stimulated: this.stimulated,
stimulation_type: this.stimulationType,
medication: {name: this.medication,
duration: '24',
frequency: this.medication_dosage_given,
dosage: this.dosage,
notes: this.notes},
medication_dosage_unit: 'ML',
medication_dosage_given: this.medication_dosage_given,
notes: this.notes,
progress_photo: this.progress_photo.name,
},{
headers: {
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
}
})
.then(response => {
console.log(response);
response.status === 201 ? this.showSwal('success-message','Carelog added') : null;
this.getFeedings(catName);
})
.catch(error => {
console.log(catID, catName);
console.log(error);
this.showSwal('auto-close', error);
})
},
I get this error...
{"cat":["This field is required."],"medication":["This field is required."]}
I have DRF on my backend and I have MultiPartParser set up in my api/views.py...(edited for brevity)
...
from rest_framework.parsers import MultiPartParser
...
class CareLogViewSet(viewsets.ModelViewSet):
queryset = CareLog.objects.all()
serializer_class = CareLogSerializer
parser_classes = (MultiPartParser,)
filter_fields = ('cat__slug', 'cat__name', 'food_type')
lookup_field = 'slug'
So why am I getting that error ?
UPDATE:
As requested, here is my template form...
<template>
<form id="carelogAddForm">
<b-collapse id="collapseForm" class="mt-2">
<fg-input label="Create New Carelog"
class="column-sizing">
<div class="row">
<div class="col-md-2">
<b-form-select v-model="food_type" :options="foodOptions"></b-form-select>
</div>
<div class="col-md-2">
<b-input v-model="amount_of_food_taken" placeholder="Amount food taken"></b-input>
</div>
<div class="col-md-2">
<b-form-input v-model="weight_before_food" placeholder="Weight Before Food"></b-form-input>
</div>
<div class="col-md-2">
<b-input v-model="weight_after_food" placeholder="Weight After Food"></b-input>
</div>
<div class="col-md-2">
<b-form-select v-model="stimulated" :options="stimulatedOps"></b-form-select>
</div>
<div class="col-md-2">
<b-form-select v-model="stimulationType" :options="stimulationTypeOps"></b-form-select>
</div>
</div>
<div class="row">
<div class="col-sm-2">
<b-form-select v-model="medication">
<option selected :value="null">Medication</option>
<option :value=catMed.name v-for="catMed in catMedications">{{catMed.name}}</option>
</b-form-select>
</div>
<div class="col-sm-2">
<b-input v-model="medication_dosage_given" placeholder="Med. Dosage"></b-input>
</div>
<div class="col-sm-4">
<!--care photo upload-->
<span v-if="window.width < 500">
<input style="display: none" type="file" #change="onPhotoUpload" ref="fileInput2">
<button id="progressImageBtn" class="btn" #click="$refs.fileInput2.click()">Upload Progress Image</button>
</span>
<span v-else>
<input class="btn btn-primary" type="file" #change="onPhotoUpload">
</span>
</div>
</div>
</fg-input>
</b-collapse>
<div class="row">
<div class="col-sm-12">
<button class="btn btn-sm btn-info float-right" #click='showButton = !showButton' v-if="showButton" v-b-toggle.collapseForm>Add New Log</button>
<button type="reset" class="btn btn-sm btn-warning float-right ml-2" #click='showButton = !showButton' v-if="!showButton" v-b-toggle.collapseForm>Cancel</button>
<button type="submit" class="btn btn-sm btn-success float-right" v-if="food_type !== 'MN' && !showButton"
v-on:click="validateSubmitNoMom(scope.item.id, scope.item.name, scope.item.slug)" #click='showButton = !showButton'>Submit</button>
<button type="submit" class="btn btn-sm btn-success float-right" v-if="food_type === 'MN' && !showButton"
v-on:click="validateSubmitMom(scope.item.id, scope.item.name)">Submit mom</button>
</div>
</div>
</form>
</template>
And my Data Object (fair warning it is long...their is much more going on in the app in general)
data () {
return {
medication: null,
modals: {
basic: false,
centered: false,
custom: false,
confirm: false
},
onFiltered: '',
variableAtParent: 'DATA FROM PARENT!',
activeName: 'first',
currentSort:'name',
currentSortDir:'asc',
collapsed: true,
medToEdit: [],
feedToEdit: [],
page: 1,
CatIndex: 0,
pagination: {
perPage: 5,
currentPage: 1,
perPageOptions: [5, 10, 25, 50],
total: 0
},
sortBy: null,
sortDesc: false,
sortDirection: 'asc',
filter: null,
searchQuery: '',
propsToSearch: ['name', 'gender', 'age', 'id', 'birthday', 'catType'],
cat: '',
cat_type: '',
example1: [],
cats: [],
thisCat: [],
catFeedings: [],
catMedications: [],
careLogTableColumns: [],
careLogColumns: [
'id',
'progressPhoto',
'foodType',
'amountOfFoodTaken',
'stimulated',
'weightBeforeFood',
'weightAfterFood',
'stimulationType',
'medication',
'medicationDosageGiven',
'actions',
],
tableColumns: [
{
key: 'id',
prop: 'id',
label: 'ID',
minWidth: 90
},
{
key: 'photo',
prop: 'photo',
label: 'Photo',
minWidth: 100
},
{
key: 'name',
prop: 'name',
label: 'Name',
minWidth: 100,
sortable: true
},
{
key: 'gender',
prop: 'gender',
label: 'Sex',
minWidth: 50,
sortable: true
},
{
key: 'birthday',
prop: 'birthday',
label: 'Birthdate',
minWidth: 140,
sortable: true
},
{
key: 'age',
prop: 'birthday',
label: 'Age',
minWidth: 100,
sortable: false
},
{
key: 'catType',
prop: 'catType',
label: 'Type',
minWidth: 60,
sortable: true
},
{
key: 'actions',
prop: 'actions',
label: 'Actions',
minWidth: 60
},
],
fuseSearch: null,
weight_before_food: '',
weight_after_food: '',
amount_of_food_taken: '',
food_type: null,
foodOptions:[
{ value: null, text: 'Food Type' },
{ value: 'MN', text: 'Mom (Nursing)' },
{ value: 'BO', text: 'Bottle' },
{ value: 'BS', text: 'Bottle/Syringe' },
{ value: 'SG', text: 'Syringe Gruel'},
{ value: 'GG', text: 'Syringe Gruel / Gruel'},
{ value: 'G', text: 'Gruel'},
],
notes: '',
stimulated: null,
stimulatedOps: [
{ value: null, text: 'Stimulated' },
'true',
'false'
],
stimulationType: null,
stimulationTypeOps: [
{ value: null, text: 'Stim. Type' },
{ value: 'UR', text: 'Urine'},
{ value: 'FE', text: 'feces'},
{ value: 'UF', text: 'Urine / Feces'},
],
showSuccess: false,
showDanger: false,
constant: 0,
dismissSecs: 4,
dismissCountDown: 0,
dismissCountDown2: 0,
nursing: false,
handleAdd: true,
showRow: true,
showButton: true,
showButton2: true,
dosage_unit: 'ML',
dosage: '',
dosageGuidelines: '',
weightBeforeFood: '',
amountOfFoodTaken: '',
foodType: '',
duration: '',
frequency: '',
name: '',
medication_dosage_given: '',
progress_photo: null,
window: {
width: 0,
height: 0
}
}
},

how to add edit button on vue-good-table in vue

I m new to Vue and stuck in a situation and don't know how to do that if anybody suggests me how I can do this let me show my code first
<div class="table-responsive-sm">
<vue-good-table
title="Shop List Table"
:columns="columns"
:rows="rows"
:paginate="true"
:lineNumbers="true"
:globalSearch="true" >
<template slot="table-row" slot-scope="props" ><a class="btn btn-sm primary" #on-row-click="onRowClick">save</a></template>
</vue-good-table>
and in script
data(){
return{
columns: [
{
label: 'Brand Name',
field: 'brand_name',
},
{
label: 'Brand Desc',
field: 'brand_desc',
},
{
label: 'Action',
field: 'before',
},
],
rows:[],
}
}
getTotals(){
var self = this;
var new1=[];
this.$http.get('/api/brands')
.then(function (response) {
self.rows=response.data
})
},
now my problem is that if I use
<span v-if="props.column.field == 'before'">
before
</span>
as suggested in this https://jsfiddle.net/aks9800/hsf0sqf8/ it throws an error like field not defined I just want to add an extra action button for edit this is vue-good table one more thing none of the action as suggested in this link for eg:- #on-row-click="onRowClick" not working
Try this
<div class="table-responsive-sm">
<vue-good-table
title="Shop List Table"
:columns="columns"
:rows="rows"
:paginate="true"
:lineNumbers="true"
:globalSearch="true" >
<template slot="table-row" slot-scope="props" >
<a class="btn btn-sm primary" #on-row-click="onRowClick">save</a>
</template>
<template slot="table-row" slot-scope="props">
<span v-if="props.column.field == 'actions'">
<a class="btn btn-sm primary" #on-row-click="onRowClick">save</a>
</span>
<span v-else>
{{props.formattedRow[props.column.field]}}
</span>
</template>
</vue-good-table>
</div>
data(){
return{
columns: [
{
label: 'Brand Name',
field: 'brand_name',
},
{
label: 'Brand Desc',
field: 'brand_desc',
},
{
label: 'Actions',
field: 'actions',
sortable: false,
}
],
rows:[],
}
}
getTotals(){
var self = this;
var new1=[];
this.$http.get('/api/brands')
.then(function (response) {
self.rows=response.data
})
},
Here is very good example how to add "edit" button in a row by marekfilip
https://jsfiddle.net/marekfilip/jm4ywzor/
html:
<div id="app">
<vue-good-table
:columns="columns"
:rows="rows" >
<template slot="table-row" slot-scope="props">
<span v-if="props.column.field == 'before'">
<button #click="editRow(props.row.id)">Edit</button>
<button #click="deleteRow(props.row.id)">Delete</button>
</span>
<span v-else>
{{props.formattedRow[props.column.field]}}
</span>
</template>
</vue-good-table>
<span>{{ text }}</span>
</div>
javascript
new Vue({
el: '#app',
data() {
return {
columns: [
{
label: 'Before',
field: 'before'
},
{
label: 'ID',
field: 'id',
sortable: true,
},
{
label: 'Text',
field: 'text',
type: 'number',
sortable: true,
},
],
rows: [
{ text: 'A', id: 1 },
{ text: 'B', id: 2 },
{ text: 'C', id: 3 },
{ text: 'D', id: 5 },
],
text: ''
};
},
methods: {
editRow(id) {
this.showAlert(id, 'EDIT')
},
deleteRow(id) {
this.showAlert(id, 'DELETE')
},
showAlert(id, type) {
this.text = `You clicked ${type} on row ID ${id}`
}
}
});

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