Reputation: 35337
I have a computed property that simply formats the date:
computed: {
items() {
return this.licenseItems.map(function(license) {
license.expires_at = moment(license.expires_at).format('MM/DD/YYYY');
return license;
});
}
}
I pass licenseItems
to a form component with the .sync
modifier and emit update:field
event from the form. In vue dev tools, I can see that licenseItems
(data) is properly updated, but items
(computed) is still showing the old data so no re-computation was performed.
I have noticed that if I remove the map and just return the licenseItems object from the computed property, it is updated. Is there some issue with Vue's computed property on mapped objects when using the sync modifier?
Upvotes: 2
Views: 1801
Reputation: 43881
You should be aware that you're modifying underlying objects in your computed. From your fiddle:
computed: {
mapped: function() {
return this.items.map(function(item) {
let original = item.date;
item.date = moment(item.date).format('MM/DD/YYYY');
console.log(original + ' => ' + item.date);
return item;
});
}
}
Your incrementDates
function also modifies the underlying objects directly.
Because each element of items
is an object, item
is a reference to that same object, so your routine updates the members of items
itself. If you intend to modify the object values, you should use a watch
instead of a computed
. If you want to have a proper computed that does not modify data items, you need to deep copy the objects.
In my example below, you can see that the data value and the computed value are distinct, but the computed is based on the data. Also, the update
event works with sync
to update the value in the parent, rather than the value being updated directly in the component. You can enter any format of date that Date
understands to set the value.
new Vue({
el: '#app',
data: {
licenseItems: [{
expires_at: Date.now()
}]
},
computed: {
items() {
return this.licenseItems.map(function(license) {
const newItem = Vue.util.extend({}, license);
newItem.expires_at = moment(license.expires_at).format('MM/DD/YYYY');
return newItem;
});
}
},
components: {
myUpdater: {
props: ['items'],
methods: {
doUpdate(event, index) {
const newObj = this.items.map(item => Vue.util.extend({}, item));
newObj[index].expires_at = new Date(event.target.value);
console.log("new object", newObj);
this.$emit('update:items', newObj);
}
}
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.1/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<my-updater :items.sync="licenseItems" inline-template>
<div>
<input v-for="item, index in items" :value="item.expires_at" @change="doUpdate($event, index)">
</div>
</my-updater>
<div v-for="item in items">
{{item.expires_at}}
</div>
</div>
Upvotes: 2