Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
151
rated 0 times [  156] [ 5]  / answers: 1 / hits: 21576  / 6 Years ago, sun, august 5, 2018, 12:00:00

I have two components: Parent and Child. The Parent has an array of cars the Child is supposed push objects the cars array. My problem is that my Child component turns cars into an object, instead of pushing an object into the cars array. My Parent component:



<template>
<child v-model=cars></child>
<ul>
<li v-for=car in cars>
{{ car.model }}
</li>
</ul>
</template>

export default {
data: function() {
return {
cars: []
}
}
}


My Child component:



<template>
<div>
<button type=button @click=addCar()>Add Car</button>
</div>
</template>

export default {
methods: {
addCar() {
this.$emit(input, { model: some car model })
}
}
}


Expected results:



cars gets updated and becomes [{ model: some car model}, { model: some car model}, etc...]



Actual results:



cars becomes an object {model: some car model}



Here is my fiddle:



https://jsfiddle.net/t121ufk5/529/



I assume something is wrong with the way i am using v-model on my child component and/or the way I am emitting is incorrect. Can someone help? Thanks in advance!


More From » vue.js

 Answers
27

Lets discuss, why you not get proper result.Then we discuss other approach to solve this problem.



Firstly we need to understand how v-model works on custom components by default.



When using a text input (including types such as email, number, etc.) or textarea, v-model=varName is equivalent to :value=varName @input=e => varName = e.target.value. This means that the value of the input is set to varName after each update to the input varName is updated to the value of the input. A normal select element will act like this too, though a multiple select will be different.



Now we need to understand,



How Does v-model Work On Components?



Since Vue doesn’t know how your component is supposed to work, or if it’s trying to act as a replacement for a certain type of input, it treats all components the same with regards to v-model. It actually works the exact same way as it does for text inputs, except that in the event handler, it doesn’t expect an event object to be passed to it, rather it expects the value to be passed straight to it. So…



<my-custom-component v-model=myProperty />



…is the same thing as…



<my-custom-component :value=myProperty @input=val => myProperty = val />



So when you apply this approach. You have to receive value as a props. and make sure you $emit name is input.



Now you can ask me at this stage,what you do wrong?



Ok, look at like code @input=val => myProperty = val



when you $emit whit a new value. this newValue will updated our parent value which you wanna update.



Here is your code this.$emit(input, { model: some car model }).



You update your parent value with a object. So your Array updated with a Object.



Lets solve the full problem.



Parent Component:
`



<template>
<child v-model=cars></child>
<ul>
<li v-for=car in cars>
{{ car.model }}
</li>
</ul>
</template>

export default {
data: function() {
return {
cars: []
}
}
}


`



Child Component:



<template>
<div>
<button type=button @click=addCar()>Add Car</button>
</div>
</template>

export default {
props: ['value']
methods: {
addCar() {
this.$emit(input, this.value.concat({model: some car model}))
}
}
}


You can actually solved it several way.



Second Approach,



Parent:



<template>
<child :cars=cars></child>
<ul>
<li v-for=car in cars>
{{ car.model }}
</li>
</ul>
</template>

export default {
data: function() {
return {
cars: []
}
}
}


Child:



<template>
<div>
<button type=button @click=addCar>Add Car</button>
</div>
</template>

export default {
props: {
cars: {
type: Array,
default:[]
}
},
methods: {
addCar() {
this.cars.push({ model: some car model })
}
}
}


Last Approach:



Parent:



    <template>
<child @update=addCar></child>
<ul>
<li v-for=car in cars>
{{ car.model }}
</li>
</ul>
</template>

export default {
data() {
return {
cars: []
}
}
},
methods: {
addCar() {
this.cars.push({ model: some car model })
}
}
}


Child:



 <template>
<div>
<button type=button @click=update>Add Car</button>
</div>
</template>

export default {
methods: {
update() {
this.$emit('update')
}
}
}

[#53805] Wednesday, August 1, 2018, 6 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
katieh

Total Points: 692
Total Questions: 104
Total Answers: 104

Location: Armenia
Member since Sat, Dec 31, 2022
1 Year ago
;