Here is a simplified version of my code:
Vue.component('entry', {
template: '\
<div>\
<label>Name: <input type="text" v-model="entry.name"></label>\
</div>\
',
props: ['entry']
});
Vue.component('entries', {
template: '\
<div>\
<entry v-for="entry in entries" :entry="entry"></entry>\
<pre>{{ combined }}</pre>\
</div>\
',
props: ['entries'],
computed: {
combined: function() {
combined = [];
this.entries.forEach(function(entry) {
combined.push(entry.name);
});
return combined.join("\n");
}
}
});
var entries = [
{name: "Entry 1"},
{name: "Entry 2"},
{name: "Entry 3"}
];
JSFiddle here: https://jsfiddle.net/msw3Lx98/3/
The top-level component (entries
) takes a list of objects, and creates a subcomponent (entry
) for each one. The subcomponent binds the entry data to an input.
When the user modifies the data by typing into one of the inputs, the top-level component needs to push the updated value of combined
to a separate bit of code.
My understanding of the watcher model is that if the top-level component watches entries
it can detect when things are added to or removed from the list, but not when data within an entry changes.
However, the top-level component clearly does see this sort of change in some way, because as the user types into an input the value of combined
gets updated.
Is there a "correct" way to detect this sort of change?
Here are a few options that I've explored:
- Define an
updated
method on the subcomponent. In that method emit a custom event, and handle this event in the parent. This is fairly awkward and I don't think it will scale very well. - Define a
beforeUpdate
method on the parent -- this (but notupdated
) runs whenever there's a change in a subcomponent. I'm not sure why, and it doesn't smell right to me. - In the top-level component, watch the
combined
property. I'm sort of surprised this works, but it does. This seems the most straightforward option, but it's not obvious from the Vue docs that computed properties are intended to be watchable, so I'm reluctant to rely on this.