I was just playing around with Vue.js and found a problem I cannot explain why it happens. Here is my MWE:
Vue.component('list-entry', { 'template': '<input type="text" :value="t" @input="fireEvent()" ref="text">', 'props': ['t', 'idx'], 'methods': { fireEvent() { this.$emit('update:t', { 'value': this.$refs.text.value, 'idx': this.idx }) } } }) new Vue({ el: "#app", data: () => ({ texts: [ 'Foo', 'Bar', 'Baz' ] }), methods: { update(ev) { console.log('Set ' + ev.value + ' at index ' + ev.idx) this.texts[ev.idx] = ev.value console.log(this.texts) } } })
input { display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <div class='container'> <list-entry v-for="(t, idx) in texts" :key="t" :t="t" :idx="idx" @update:t="update($event)" ></list-entry> </div> {{ texts }} </div>
Let me explain it a bit. There is a global data property texts
that contains a few strings. For each of these strings, a custom component list-entry
is generated. The strings are propagated using v-bind
to these components.
Upon change of the text in the inputs, I want to update the global data property. Therefore a update:t
event is fired and listened on in the main app. Here the update(ev)
function should do the things.
If you run it you will see that in the console, the corresponding messages appear and the array is updated as well. However, in the output on the HTML screen (replaced from {{ texts }}
), the value is not updated.
Now I am confused. Is the data property updated or not? Why is it not visible in the mustache output? Why is it correctly output in the console at the same time?
Advertisement
Answer
You could achieve the desired behavior with a short code by using Using v-model
on Components
Vue.component('list-entry', { 'template': `<input type="text" :value="value" @input="$emit('input', $event.target.value)" />`, props: ['value'], }) new Vue({ el: "#app", data: () => ({ texts: [ 'Foo', 'Bar', 'Baz' ] }), })
input { display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <div class='container'> <list-entry v-for="(t, idx) in texts" :key="idx" v-model="texts[idx]"></list-entry> </div> {{ texts }} </div>