Vue.js - emit to update array not working

It is possible to trigger the event of updating the transmitted value in props

In the parent

<my-component :is-open.sync="isOpen" />

In my-component

this.$emit('update:isOpen', true)

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')
            }
        }
    }