I've created a simple component named DefaultButton.
It bases on properties, that are being set up whenever this component is being created.
The point is that after mounting it, It does not react on changes connected with "defaultbutton", that is an object located in properties
<template>
<button :class="buttonClass" v-if="isActive" #click="$emit('buttonAction', defaultbutton.id)" >
{{ this.defaultbutton.text }}
</button>
<button :class="buttonClass" v-else disabled="disabled">
{{ this.defaultbutton.text }}
</button>
</template>
<script>
export default {
name: "defaultbutton",
props: {
defaultbutton: Object
},
computed: {
buttonClass() {
return `b41ngt ${this.defaultbutton.state}`;
},
isActive() {
return (this.defaultbutton.state === "BUTTON_ACTIVE" || this.defaultbutton.state === "BUTTON_ACTIVE_NOT_CHOSEN");
}
}
};
</script>
Having following component as a parent one:
<template>
<div v-if="state_items.length == 2" class="ui placeholder segment">
{{ this.state_items[0].state }}
{{ this.state_items[1].state }}
{{ this.current_active_state }}
<div class="ui two column very relaxed stackable grid">
<div class="column">
<default-button :defaultbutton="state_items[0]" #buttonAction="changecurrentstate(0)"/>
</div>
<div class="middle aligned column">
<default-button :defaultbutton="state_items[1]" #buttonAction="changecurrentstate(1)"/>
</div>
</div>
<div class="ui vertical divider">
Or
</div>
</div>
</template>
<script type="text/javascript">
import DefaultButton from '../Button/DefaultButton'
export default {
name: 'changestatebox',
data() {
return {
current_active_state: 1
}
},
props: {
state_items: []
},
components: {
DefaultButton
},
methods: {
changecurrentstate: function(index) {
if(this.current_active_state != index) {
this.state_items[this.current_active_state].state = 'BUTTON_ACTIVE_NOT_CHOSEN';
this.state_items[index].state = 'BUTTON_ACTIVE';
this.current_active_state = index;
}
},
},
mounted: function () {
this.state_items[0].state = 'BUTTON_ACTIVE';
this.state_items[1].state = 'BUTTON_ACTIVE_NOT_CHOSEN';
}
}
</script>
It clearly shows, using:
{{ this.state_items[0].state }}
{{ this.state_items[1].state }}
{{ this.current_active_state }}
that the state of these items are being changed, but I am unable to see any results on the generated "DefaultButtons". Classes of objects included in these components are not being changed.
#edit
I've completely changed the way of delivering the data.
Due to this change, I've abandoned the usage of an array; instead I've used two completely not related object.
The result is the same - class of the child component's object is not being
DefaulButton.vue:
<template>
<button :class="buttonClass" v-if="isActive" #click="$emit('buttonAction', defaultbutton.id)" >
{{ this.defaultbutton.text }}
</button>
<button :class="buttonClass" v-else disabled="disabled">
{{ this.defaultbutton.text }}
</button>
</template>
<style lang="scss">
import './DefaultButton.css';
</style>
<script>
export default {
name: "defaultbutton",
props: {
defaultbutton: {
type: Object,
default: () => ({
id: '',
text: '',
state: '',
})
}
},
computed: {
buttonClass() {
return `b41ngt ${this.defaultbutton.state}`;
},
isActive() {
return (this.defaultbutton.state === "BUTTON_ACTIVE" ||
this.defaultbutton.state === "BUTTON_ACTIVE_NOT_CHOSEN");
}
}
};
</script>
ChangeStateBox.vue:
<template>
<div class="ui placeholder segment">
{{ this.state_first.state }}
{{ this.state_second.state }}
{{ this.current_active_state }}
<div class="ui two column very relaxed stackable grid">
<div class="column">
<default-button :defaultbutton="state_first" #buttonAction="changecurrentstate(0)"/>
</div>
<div class="middle aligned column">
<default-button :defaultbutton="state_second" #buttonAction="changecurrentstate(1)"/>
</div>
</div>
<div class="ui vertical divider">
Or
</div>
</div>
</template>
<script type="text/javascript">
import DefaultButton from '../Button/DefaultButton'
export default {
name: 'changestatebox',
data() {
return {
current_active_state: 1
}
},
props: {
state_first: {
type: Object,
default: () => ({
id: '',
text: ''
})
},
state_second: {
type: Object,
default: () => ({
id: '',
text: ''
})
},
},
components: {
DefaultButton
},
methods: {
changecurrentstate: function(index) {
if(this.current_active_state != index) {
if(this.current_active_state == 1){
this.$set(this.state_first, 'state', "BUTTON_ACTIVE_NOT_CHOSEN");
this.$set(this.state_second, 'state', "BUTTON_ACTIVE");
} else {
this.$set(this.state_first, 'state', "BUTTON_ACTIVE");
this.$set(this.state_second, 'state', "BUTTON_ACTIVE_NOT_CHOSEN");
}
this.current_active_state = index;
}
},
},
created: function () {
this.state_first.state = 'BUTTON_ACTIVE';
this.state_second.state = 'BUTTON_ACTIVE_NOT_CHOSEN';
}
}
</script>
You're declaring props wrong. It is either an array of prop names or it is an object with one entry for each prop declaring its type, or it is an object with one entry for each prop declaring multiple properties.
You have
props: {
state_items: []
},
but to supply a default it should be
props: {
state_items: {
type: Array,
default: []
}
},
But your problem is most likely that you're mutating state_items in such a way that Vue can't react to the change
Your main problem is the way you are changing the button state, according with Array change detection vue can't detect mutations by indexing.
Due to limitations in JavaScript, Vue cannot detect the following
changes to an array:
When you directly set an item with the index, e.g.
vm.items[indexOfItem] = newValue When you modify the length of the
array, e.g. vm.items.length = newLength
In case someone will be having the same issue:
#Roy J as well as #DobleL were right.
The reason behind this issue was related with the wrong initialization of state objects.
According to the documentation:
Vue cannot detect property addition or deletion.
Since Vue performs the getter/setter conversion process during instance
initialization, a property must be present in the
data object in order for Vue to convert it and make it reactive.
Before reading this sentence, I used to start with following objects as an initial data:
var local_state_first = {
id: '1',
text: 'Realized',
};
var local_state_second = {
id: '2',
text: 'Active'
};
and the correct version of it looks like this:
var local_state_first = {
id: '1',
text: 'Realized',
state: 'BUTTON_ACTIVE'
};
var local_state_second = {
id: '2',
text: 'Active',
state: 'BUTTON_ACTIVE'
};
whereas declaring the main component as:
<change-state-box :state_first="local_state_first" :state_second="local_state_second" #buttonAction="onbuttonAction"/>
Rest of the code remains the same ( take a look at #edit mark in my main post )
Related
Am very new to vuejs.am trying to replicate the javascript with vue. where a user can toggle button. I have a list of buttons and I would like to toggle the active class but remove the active class from all other buttons.. Is there a better way of writtting the function without the querySelector? Am really stuck..
<template>
<div #click="selectItem" class="menu-tabs">
<button type="btn" class="menu-tab-item active" data-target="#remis-transfer"> Transfer
</button>
<button type="btn" class="menu-tab-item text-muted" data-target="#bank-transfer">
Transfer Money
</button>
<button type="btn" class="menu-tab-item text-muted" data-target="#fueling">
Fueling
</button>
</div>
</template>
<script>
export default {
methods: {
selectItem(e) {
if (e.target.classList.contains("menu-tab-item") && !e.target.classList.contains("active")) {
const target = e.target.getAttribute("data-target")
menuTabs.querySelector(".active").classList.remove("active");
e.target.classList.add("active");
const menuSection = document.querySelector(".menu-section");
menuSection.querySelector(".menu-tab-content.active").classList.remove("active");
menuSection.querySelector(target).classList.add('active');
}
}
}
}
</script>
Look at the code
var Main = {
data() {
return {
active: 0,
buttonList: [
{
text: "Transfer",
target: "#remis-transfer",
},
{
text: "Transfer Money",
target: "#bank-transfer",
},
{
text: "Fueling",
target: "#fueling",
},
],
};
},
methods: {
selectItem(i) {
this.active = i;
},
},
};
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<div id="app">
<div class="menu-tabs">
<button
type="btn"
class="menu-tab-item"
v-for="(item, index) in buttonList"
:class="[{ active: active == index }, { 'text-muted': active != index }]"
:data-target="item.target"
:key="index"
#click="selectItem(index)"
>
{{ item.text }}
</button>
</div>
</div>
You can simply define some states like:
data() {
return {
myActiveClass: 'active',
myMutedClass: 'text-muted'
}
},
and pass this myActiveClass and myMutedClass states to your elements like this:
class=menu-tab-item ${myMutedClass} ${myActiveClass}
with this approach, you can quickly achieve what you want. So when you want an element to not be active, in your function you can make myActiveClass = '', or if you want the text to lose muted class you can say myMutedClass = '' .
Just make sure to play with states in the way you want.
I'm working with BootstrapVue. To my problem: I have a v-for in my template in which I have two buttons.
Looping over my v-for my v-if doesn't generate unique IDs and than after clicking one button each button will be triggered (from Open me! to Close me! and other way around).
How can I manage to get each button only triggers itself and doesn't affect the other?
I think I have to use my n of my v-for but I actually don't know how to bind this to a v-if..
Thanks in advance!
<template>
<div>
<div v-for="n in inputs" :key="n.id">
<b-button v-if="hide" #click="open()">Open me!</b-button>
<b-button v-if="!hide" #click="close()">Close me! </b-button>
</div>
<div>
<b-button #click="addInput">Add Input</b-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
id: null,
inputs: [{
id: 0
}],
hide: true,
};
},
methods: {
open() {
this.hide = false
},
close() {
this.hide = true
},
addInput() {
this.inputs.push({
id: this.id += 1;
})
}
}
};
</script>
Everything seems to look fine. In order to handle each button triggers,
you can maintain an object like so:
<script>
export default {
data() {
return {
inputs: [{id: 0, visible: false}],
};
},
methods: {
open(index) {
this.inputs[index].visible = false
},
close(index) {
this.inputs[index].visible = true
},
addInput() {
this.inputs.push({id: this.inputs.length, visible: false});
}
}
};
</script>
and your template should be like
<template>
<div>
<div v-for="(val, index) in inputs" :key="val.id">
<b-button v-if="val.visible" #click="open(index)">Open me!</b-button>
<b-button v-if="!val.visible" #click="close(index)">Close me! </b-button>
</div>
</div>
</template>
Edit:
You don't need to insert an id every time you create a row, instead can use the key as id. Note that the inputs is an object and not array so that even if you want to delete a row, you can just pass the index and get it removed.
I would create an array of objects. Use a boolean as property to show or hide the clicked item.
var app = new Vue({
el: '#app',
data: {
buttons: []
},
created () {
this.createButtons()
this.addPropertyToButtons()
},
methods: {
createButtons() {
// Let's just create buttons with an id
for (var i = 0; i < 10; i++) {
this.buttons.push({id: i})
}
},
addPropertyToButtons() {
// This method add a new property to buttons AFTER its generated
this.buttons.forEach(button => button.show = true)
},
toggleButton(button) {
if (button.show) {
button.show = false
} else {
button.show = true
}
// We are changing the object after it's been loaded, so we need to update ourselves
app.$forceUpdate();
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template>
<div>
<div v-for="button in buttons" :key="button.id">
<button v-if="button.show" #click="toggleButton(button)">Open me!</button>
<button v-if="!button.show" #click="toggleButton(button)">Close me! </button>
</div>
</div>
</template>
</div>
I'm trying to build a simple page builder which has a row elements, its child column elements and the last the component which I need to call. For this I designed and architecture where I'm having the dataset defined to the root component and pushing the data to its child elements via props. So let say I have a root component:
<template>
<div>
<button #click.prevent="addRowField"></button>
<row-element v-if="elements.length" v-for="(row, index) in elements" :key="'row_index_'+index" :attrs="row.attrs" :child_components="row.child_components" :row_index="index"></row-element>
</div>
</template>
<script>
import RowElement from "../../Components/Builder/RowElement";
export default {
name: "edit",
data(){
return{
elements: [],
}
},
created() {
this.listenToEvents();
},
components: {
RowElement,
},
methods:{
addRowField() {
const row_element = {
component: 'row',
attrs: {},
child_components: [
]
}
this.elements.push(row_element)
}
},
}
</script>
Here you can see I've a button where I'm trying to push the element and its elements are being passed to its child elements via props, so this RowElement component is having following code:
<template>
<div>
<column-element v-if="child_components.length" v-for="(column,index) in child_components" :key="'column_index_'+index" :attrs="column.attrs" :child_components="column.child_components" :row_index="row_index" :column_index="index"></column-element>
</div>
<button #click="addColumn"></button>
</template>
<script>
import ColumnElement from "./ColumnElement";
export default {
name: "RowElement",
components: {ColumnElement},
props: {
attrs: Object,
child_components: Array,
row_index: Number
},
methods:{
addColumn(type, index) {
this.selectColumn= false
let column_element = {
component: 'column',
child_components: []
};
let component = {}
//Some logic here then we are emitting event so that it goes to parent element and there it can push the columns
eventBus.$emit('add-columns', {column: column_element, index: index});
}
}
}
</script>
So now I have to listen for event on root page so I'm having:
eventBus.$on('add-columns', (data) => {
if(typeof this.elements[data.index] !== 'undefined')
this.elements[data.index].child_components.push(data.column)
});
Now again I need these data accessible to again ColumnComponent so in columnComponent file I have:
<template>
//some extra div to have extended features
<builder-element
v-if="!loading"
v-for="(item, index) in child_components"
:key="'element_index_'+index" :column_index="column_index"
:element_index="index" class="border bg-white"
:element="item" :row_index="row_index"
>
</builder-element>
</template>
<script>
export default {
name: "ColumnElement",
props: {
attrs: Object,
child_components: Array,
row_index: Number,
column_index: Number
},
}
</script>
And my final BuilderElement
<template>
<div v-if="typeof element.component !== 'undefined'" class="h-10 w-10 mt-1 mb-2 mr-3 cursor-pointer font-bold text-white rounded-lg">
<div>{{element.component}}</div>
<img class="h-10 w-10 mr-3" :src="getDetails(item.component, 'icon')">
</div>
<div v-if="typeof element.component !== 'undefined'" class="flex-col text-left">
<h5 class="text-blue-500 font-bold">{{getDetails(item.component, 'title')}}</h5>
<p class="text-xs text-gray-600 mt-1">{{getDetails(item.component, 'desc')}}</p>
</div>
</template>
<script>
export default {
name: "BuilderElement",
data(){
return{
components:[
{id: 1, title:'Row', icon:'/project-assets/images/row.png', desc:'Place content elements inside the row', component_name: 'row'},
//list of rest all the components available
]
}
},
props: {
element: Object,
row_index: Number,
column_index: Number,
element_index: Number,
},
methods:{
addElement(item,index){
//Some logic to find out details
let component_element = {
component: item.component_name,
attrs: {},
child_components: [
]
}
eventBus.$emit('add-component', {component: component_element, row_index: this.row_index, column_index: this.column_index, element_index: this.element_index});
},
getDetails(component, data) {
let index = _.findIndex(this.components, (a) => {
return a.component_name === component;
})
console.log('Component'+ component);
console.log('Index '+index);
if(index > -1) {
let component_details = this.components[index];
return component_details[data];
}
else
return null;
},
},
}
</script>
As you can see I'm again emitting the event named add-component which is again listened in the root component so for this is made following listener:
eventBus.$on('add-component', (data) => {
this.elements[data.row_index].child_components[data.column_index].child_components[data.element_index] = data.component
});
which shows the data set in my vue-devtools but it is not appearing in the builder element:
Images FYR:
This is my root component:
This is my RowComponent:
This is my ColumnComponent:
This is my builder element:
I don't know why this data not getting passed to its child component, I mean last component is not reactive to props, any better idea is really appreciated.
Thanks
The issue is with the way you're setting your data in the addComponent method.
Vue cannot pick up changes when you change an array by directly modifying it's index, something like,
arr[0] = 10
As defined in their change detection guide for array mutations,
Vue wraps an observed array’s mutation methods so they will also
trigger view updates. The wrapped methods are:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
So you can change.
this.elements[data.row_index].child_components[data.column_index].child_components[data.element_index] = data.component
To,
this.elements[data.row_index].child_components[data.column_index].child_components.splice(data.element_index, 1, data.component);
If I have a template as such with FruitPrices as a component:
<template>
<div id="app">
<div>
<span #click=SOME_FUNCTION> Change currency </span>
<FruitPrices fruit="apple"></FruitPrices>
<FruitPrices fruit="banana"></FruitPrices>
<FruitPrices fruit="orange"></FruitPrices>
...
....
.....
</template>
...
...
...
import FruitPrices from ./component/FruitPrices.vue
I was wondering would it be possible to have SOME_FUNCTION be a method that alters the currency across all the FruitPrices Components? i.e. if some components are in USD, some are in GBP, can I set them all to Euros via a method in the current main App.?
You could set a property in the data object for currency and use that across all components and have a function alter it.
data() {
return {
currency: "USD",
...
}
},
methods: {
changeCurrency(newCurrency){
this.currency = newCurrency;
}
}
and in the template
<span #click=changeCurrency('Euro')> Change currency </span>
Let's use this component to pass the currency, price and fruit to each component FruitPrices component:
<template>
<div>
<!-- USD is selected by default, once the option change, the prices will be updated -->
<select v-model="currency">
<!-- allows to select one currency at time, it shows all the currencies
that exist in the currencies array data property -->
<option
v-for="(currencyOption, index) in currencies"
:key="index"
:value="currencyOption"
>
<!-- show only the currency name as option -->
{{ currencyOption.name }}
</option>
</select>
<div v-for="(fruit, fruitIndex) in fruitsWithPrices" :key="fruitIndex">
<!-- if everything is working fine, you don't need close tags for empty
custom component, you can use '/' at the end of the first tag to self close it-->
<FruitPrices :name="fruit.name" :convertedPrice="fruit.convertedPrice" />
</div>
</div>
</template>
<script>
import FruitPrices from '../somePlace/FruitPrices'
export default {
name: "FruitPricesContainer",
components: { FruitPrices },
data: () => ({
fruits: [
{
name: 'Apple',
price: 0.2
},
{
name: 'Banana',
price: 0.3
},
{
name: 'Orange',
price: 0.25
}
],
currency: {
// Base currency, exchangeRate = 1
exchangeRate: 1,
name: 'USD'
},
// Used exchange rates only for demo purpose, not are the real and valid exchange rates
currencies: [
{
exchangeRate: 1,
name: 'USD'
},
{
exchangeRate: 1.2,
name: 'EUR'
},
{
exchangeRate: 0.7,
name: 'SGD'
},
{
exchangeRate: 700,
name: 'MXN'
},
{
exchangeRate: 3700,
name: 'COP'
}
]
}),
computed: {
// The fruitsWithPrices listen for changes in both, the fruit and
// the currency, so once you change it by selecting a different currency
// the prices will be updated automatically (nice)
fruitsWithPrices() {
return this.fruits.map((fruit) => {
return {
...fruit, // Add name and original price to the returned object
convertedPrice: fruit.price * this.currency.exchangeRate // Add the price based on the exchange rate
}
})
}
}
}
</script>
Now, let's create the FruitPrices component:
<template>
<div>
<p>{{ name }}: {{ convertedPrice }}</p>
</div>
</template>
<script>
export default {
name: "FruitPrices",
props: {
name: {
type: String,
required: true
},
convertedPrice: {
type: Number,
required: true
}
}
}
</script>
And it's ready! (Tbh, I didn't test it, please let me know if you have errors or problems).
I don't know if I got the logic of your problem but maybe you can use the vue props like this:
<FruitPrices fruit="apple" :currency="newCurrency || 'USD'"></FruitPrices>
<FruitPrices fruit="banana" :currency="newCurrency || 'GBP'"></FruitPrices>
<FruitPrices fruit="orange" :currency="newCurrency || 'USD'"></FruitPrices>
you can define the props currency inside the component FruitPrices. If the currency prop is not defined then the second currency is going to be taken as default (for example "newCurrency || 'GBP'" if newCurrency is null then the currency GBP is taken as default).
Vue docs for props: https://v2.vuejs.org/v2/guide/components-props.html
Then in the main template component, you define the variable newCurrency and you pass that variable to the prop currency of the component FruitPrices:
data: () => {
newCurrency: null
},
methods: {
setNewCurrency() {
this.newCurrency = this.someFieldOfYourForm;
}
}
I have a data structure with nested objects that I want to bind to sub-components, and I'd like these components to edit the data structure directly so that I can save it all from one place. The structure is something like
job = {
id: 1,
uuid: 'a-unique-value',
content_blocks: [
{
id: 5,
uuid: 'some-unique-value',
block_type: 'text',
body: { en: { content: 'Hello' }, fr: { content: 'Bonjour' } }
},
{
id: 9,
uuid: 'some-other-unique-value',
block_type: 'text',
body: { en: { content: 'How are you?' }, fr: { content: 'Comment ça va?' } }
},
]
}
So, I instantiate my sub-components like this
<div v-for="block in job.content_blocks" :key="block.uuid">
<component :data="block" :is="contentTypeToComponentName(block.block_type)" />
</div>
(contentTypeToComponentName goes from text to TextContentBlock, which is the name of the component)
The TextContentBlock goes like this
export default {
props: {
data: {
type: Object,
required: true
}
},
created: function() {
if (!this.data.body) {
this.data.body = {
it: { content: "" },
en: { content: "" }
}
}
}
}
The created() function takes care of adding missing, block-specific data that are unknown to the component adding new content_blocks, for when I want to dynamically add blocks via a special button, which goes like this
addBlock: function(block_type) {
this.job.content_blocks = [...this.job.content_blocks, {
block_type: block_type,
uuid: magic_uuidv4_generator(),
order: this.job.content_blocks.length === 0 ? 1 : _.last(this.job.content_blocks).order + 1
}]
}
The template for TextContentBlock is
<b-tab v-for="l in ['fr', 'en']" :key="`${data.uuid}-${l}`">
<template slot="title">
{{ l.toUpperCase() }} <span class="missing" v-show="!data.body[l] || data.body[l] == ''">(missing)</span>
</template>
<b-form-textarea v-model="data.body[l].content" rows="6" />
<div class="small mt-3">
<code>{{ { block_type: data.block_type, uuid: data.uuid, order: data.order } }}</code>
</div>
</b-tab>
Now, when I load data from the API, I can correctly edit and save the content of these blocks -- which is weird considering that props are supposed to be immutable.
However, when I add new blocks, the textarea above wouldn't let me edit anything. I type stuff into it, and it just deletes it (or, I think, it replaces it with the "previous", or "initial" value). This does not happen when pulling content from the API (say, on page load).
Anyway, this led me to the discovery of immutability, I then created a local copy of the data prop like this
data: function() {
return {
block_data: this.data
}
}
and adjusted every data to be block_data but I get the same behaviour as before.
What exactly am I missing?
As the OP's comments, the root cause should be how to sync textarea value between child and parent component.
The issue the OP met should be caused by parent component always pass same value to the textarea inside the child component, that causes even type in something in the textarea, it still bind the same value which passed from parent component)
As Vue Guide said:
v-model is essentially syntax sugar for updating data on user input
events, plus special care for some edge cases.
The syntax sugar will be like:
the directive=v-model will bind value, then listen input event to make change like v-bind:value="val" v-on:input="val = $event.target.value"
So adjust your codes to like below demo:
for input, textarea HTMLElement, uses v-bind instead of v-model
then uses $emit to popup input event to parent component
In parent component, uses v-model to sync the latest value.
Vue.config.productionTip = false
Vue.component('child', {
template: `<div class="child">
<label>{{value.name}}</label><button #click="changeLabel()">Label +1</button>
<textarea :value="value.body" #input="changeInput($event)"></textarea>
</div>`,
props: ['value'],
methods: {
changeInput: function (ev) {
let newData = Object.assign({}, this.value)
newData.body = ev.target.value
this.$emit('input', newData) //emit whole prop=value object, you can only emit value.body or else based on your design.
// you can comment out `newData.body = ev.target.value`, then you will see the result will be same as the issue you met.
},
changeLabel: function () {
let newData = Object.assign({}, this.value)
newData.name += ' 1'
this.$emit('input', newData)
}
}
});
var vm = new Vue({
el: '#app',
data: () => ({
options: [
{id: 0, name: 'Apple', body: 'Puss in Boots'},
{id: 1, name: 'Banana', body: ''}
]
}),
})
.child {
border: 1px solid green;
}
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<span> Current: {{options}}</span>
<hr>
<div v-for="(item, index) in options" :key="index">
<child v-model="options[index]"></child>
</div>
</div>