I already know that editing object within an array doesn't work for vue.js due to its limited capability and base on what I read using vue.set should solve this problem easily but I am having a hard time making it work.
this is my sample data. The parent object is called resource and inside resource there are power_generator_groups , inside the power_generator_groups are power_generators.
{
"id": 5,
"bg_member_id": 1,
"code": "G0633",
"name": "namex1",
"power_generator_groups": [
{
"id": 1,
"resource_id": 5,
"code": "GC033",
"power_generators": [
{
"id": 1,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
},
{
"id": 2,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
},
{
"id": 3,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
}
]
},
{
"id": 2,
"resource_id": 5,
"code": "GC033",
"contract_number": "065C001",
"power_generators": [
{
"id": 4,
"power_generator_group_id": 2,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
}
]
}
]
}
and this is my vue file
<template lang="pug">
.wrapper
.animated.fadeIn
b-container(fluid='')
b-row.my-1
b-col(sm='3')
label(:for='`type-key`') companyName
b-col(sm='9')
b-form-select(v-model='item.bg_member_id' :options="companyList")
b-col(sm='3')
label(:for='`type-key`') code
b-col(sm='9')
b-form-input(v-model='item.code')
b-button(size='sm', @click='addPowerGeneratorGroup', variant="primary")
| Add power_generator_group
template(v-for='(group, group_index) in item.power_generator_groups')
b-card(
header-tag="header"
footer-tag="footer"
)
div(slot="header")
i.fa.fa-align-justify
strong power_generator_groups
button.btn.btn-default.btn-sm(type='button' @click='deletePowerGeneratorGroup(group_index)')
span.fa.fa-trash-o
div
b-row.my-1
b-col(sm='3')
label(:for='`type-key`')
| code
b-col(sm='9')
b-form-input(v-model='group.code')
b-col(sm='3')
label(:for='`type-key`') group name
b-col(sm='9')
b-form-input(v-model='group.name')
b-col(sm='3')
label(:for='`type-key`') contract number
b-col(sm='9')
b-form-input(v-model='group.contract_number')
b-container.bv-example-row(fluid='')
b-button(size='sm', @click='addPowerGenerator(group_index)', variant="primary")
| add power_generator
b-card(
header-tag="header"
footer-tag="footer"
)
div(slot="header")
i.fa.fa-align-justify
strong power_generators
b-table(small v-bind:item="group.power_generators" v-bind:fields="fields" fixed responsive)
template(v-for="field in fields" :slot="field.key" slot-scope="contract")
template(v-if="field.key == 'actions'")
b-button(size='sm', @click='deletePowerGenerator(group_index, contract.index)', variant="primary")
| Del
template(v-else)
b-form-input(:type='types[field.key]' v-model = 'contract.item[field.key]')
b-button(size='sm', @click='save', variant="primary")
| Save
</template>
<script>
import Vue from 'vue';
export default {
props: {
item: {
type: Object,
required: true,
default: () => {
}
},
companyList: Array
},
data() {
return {
companyId: null,
code: null,
name: null,
contract_number: null,
fields: [
{key: 'actions', label: '' },
{key: 'code', label: 'code', sortable: true, sortDirection: 'desc'},
{key: 'name', label: 'name', sortable: true, class: 'text-center'},
{key: 'contract_number', label: 'contractNo'},
{key: 'supply_max', label: 'maxunit'}
],
types: {
code: 'text',
name: 'text',
contract_number: 'text',
supply_max: 'number'
},
items:
{}
}
},
mounted() {
},
computed: {},
methods: {
addPowerGenerator(index) {
console.log(index)
console.log(this.item)
const pgg = this.item.power_generator_groups[index];
const pgs = pgg.power_generators || Vue.set(pgg, 'power_generators', []);
pgs.push(
{
"code": "",
"name": "",
"contract_number": "",
"supply_max": "",
}
)
},
addPowerGeneratorGroup() {
const pggs = this.item.power_generator_groups || Vue.set(this.item, 'power_generator_groups', []);
pggs.push(
{
"resource_id": this.item.id,
"name": "",
"code": "",
"contract_number": "",
"power_generators": []
}
)
},
deletePowerGenerator(group_index, field_index) {
this.item.power_generator_groups[group_index].power_generators.splice(field_index, 1);
},
deletePowerGeneratorGroup(group_index) {
this.item.power_generator_groups.splice(group_index, 1);
},
save: function () {
this.$parent.save(this.item)
}
}
}
</script>
You'll need Vue.set
only if you have power_generator_groups
that have no power_generators
property, since Vue can't detect when you add it otherwise.
Assuming there are no problems with your template (you didn't show it), change your addPowerGenerator
method:
addPowerGenerator(index) {
console.log(index)
console.log(this.item)
const pgg = this.item.power_generator_groups[index];
const pgs = pgg.power_generators || Vue.set(pgg, 'power_generators', []);
pgs.push(
{
"code": "",
"name": "",
"contract_number": "",
"supply_max": "",
}
)
}
Vue.set
returns the property you just created which is how pgs
contains the proper reference in that case.
Do the same thing for the new method you edited in:
addPowerGeneratorGroup() {
const pggs = this.item.power_generator_groups || Vue.set(this.item, 'power_generator_groups', []);
pggs.push(
{
"resource_id": this.item.id,
"name": "",
"code": "",
"contract_number": "",
"power_generators": []
}
)
}
You can see a mockup here where I've assumed this.item
refers to the resource itself. I included a 3rd group which has no power_generators
property for testing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With