'v-model' directives cannot update the iteration variable itself

My solution was very simple (see v-model="tags[index]"):

Instead of doing this:

<template v-for="tag in tags">
    <TagView :key="tag.key" v-model="tag" />
</template>

You should do this:

<template v-for="(tag, index) in tags">
    <TagView :key="tag.key" v-model="tags[index]" />
</template>

The reason is you cannot pass iterated object tag into v-model for modifications. Please find more info about this: Iterating a list of objects with foreach


I think we shouldn't modify the passed data to a slot, pretty much like component props. However, I think it could be a bug.

1st approach

The v-model directive works using a nested field in the passed data to the slot.

<!DOCTYPE html>
<html>
<head>
<script src="http://vuejs.org/js/vue.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <div id="app">
    <custom-component v-model="tags">
      <div slot-scope="{tags,addTag,input}">
        <span v-for="tag in tags">
          {{tag}}
        </span>
        <input type="text" @keydown.enter.prevent="addTag" v-model="input.value">
      </div>
    </custom-component>
  </div>
</body>
</html>
Vue.component('custom-component',{
  props:['value'],
  data(){
    return {
      input: {
        value: ''
      }
    }
  },
  methods:{
    addTag(){
      this.$emit('input',[...this.value,this.input.value])
      console.log([...this.value,this.input.value])
      this.input.value = ''
    }
  },
  render(h){
    return this.$scopedSlots.default({
      tags:this.value,
      addTag:this.addTag,
      input:this.input
    })
  }
})


new Vue({
  el:'#app',
  data:{
    tags:[
      'Test',
      'Design'
    ]
  }
})

2nd approach

Use the input event to get the input value attribute directly

<!DOCTYPE html>
<html>
<head>
<script src="http://vuejs.org/js/vue.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <div id="app">
    <custom-component v-model="tags">
      <div slot-scope="{tags,addTag}">
        <span v-for="tag in tags">
          {{tag}}
        </span>
        <input type="text" @keydown.enter.prevent="addTag">
      </div>
    </custom-component>
  </div>
</body>
</html>
Vue.component('custom-component',{
  props:['value'],
  data(){
    return {
      newTag:''
    }
  },
  methods:{
    addTag(evt){
      console.log(evt.target.value)
       this.$emit('input',[...this.value, evt.target.value])
      evt.target.value = ''
    }
  },
  render(h){
    return this.$scopedSlots.default({
      tags:this.value,
      addTag:this.addTag,
      newTag:this.newTag
    })
  }
})


new Vue({
  el:'#app',
  data:{
    tags:[
      'Test',
      'Design'
    ]
  }
})

You can also check these related issues:

StackOverflow

Using v-model inside scoped slots

Issues and Forum

https://forum.vuejs.org/t/v-model-and-slots/17616

https://github.com/vuejs/vue/issues/9726


Consider the following two JavaScript examples:

for (let value of array) {
  value = 10
}
function (value) {
  value = 10
}

In both cases trying to assign 10 to value will only have an effect locally, it won't have any impact beyond the local scope. The caller, for example, would not be affected by the change.

Now consider these two examples where an object is used instead, where the object is of the form { value: 9 }:

for (let valueWrapper of array) {
  valueWrapper.value = 10
}
function (valueWrapper) {
  valueWrapper.value = 10
}

In this case the change is not limited to the local scope as we're updating objects. External code, such as the caller of the function, would also be impacted by this change to the value property as it can see the same object.

These examples are equivalent to trying to update a value using v-model in a variety of cases. The first two examples are equivalent to:

<template v-for="value in array">
  <input v-model="value">
</template>

and:

<template v-slot="{ value }">
  <input v-model="value">
</template>

The arguments passed to v-slot can very much be thought of as analogous to function parameters. Neither the loop nor the scoped slot would work as desired, exactly the same as they don't for their pure JavaScript equivalents.

However, the latter two of my four examples would be equivalent to:

<template v-for="valueWrapper in array">
  <input v-model="valueWrapper.value">
</template>

and:

<template v-slot="{ valueWrapper }">
  <input v-model="valueWrapper.value">
</template>

These should work fine as they are updating a property on an object.

However, to go back to the original question, it's important that we're binding the appropriate object. In this case we would need to bind the newTag property of the component. Copying that property to another object wouldn't work either as v-model would just be updating an irrelevant object.