I have a fairly complicated object with nested components. It looks sort of like this (stripped down for easier reading):
<script type="text/x-template" id="fieldset-template">
<div class="fieldset">
<div class="fieldset-repetition" v-for="(repetition, key) in repetitions">
<div class="field-list">
<field v-for="field in fields" v-bind:key="field.key" v-bind:fieldset="field.fieldset" v-bind:fieldset-key="key" v-bind:field-data="field"></field>
</div>
<div class="repetition-meta">
<a class="move-repetition" v-on:click="moveUp(key)">Up</a>
</div>
</div>
</div>
</script>
<script type="text/x-template" id="field-template">
<div class="field">
<div class="form-group">
<label class="control-label" v-html="name"></label>
<div class="field-repetition" v-for="(repetition, key) in repetitions">
<div class="field-text">
<input class="form-control" v-model="values[key]" />
</div>
</div>
</div>
</div>
</script>
<script>
Vue.component('set', {
components: {
field: {
created: function() {
// populate with data
this.populateData();
},
data: function() {
return {
repetitions: [],
values: [],
}
},
methods: {
populateData: function() {
this.repetitions = this.fieldData.repetitions;
this.repetitions.forEach(function(repetition, key) {
this.values = this.fieldData.value[this.fieldsetKey];
}.bind(this));
},
repeatField: function() {
var field = Object.clone(this);
delete field.repetitions;
this.repetitions.push(field);
if (this.widget != 'checkbox') {
this.values.push(this.fieldData.default);
}
else {
this.values.push([this.fieldData.default]);
}
},
},
props: {
fieldData: {
type: Object
},
fieldset: {
type: Object
},
fieldsetKey: {
type: Number
}
},
template: '#field-template'
}
},
data: function() {
return {
fields: [FieldObject1, FieldObject2, FieldObject3],
repetitions: [RepetitionObject1, RepetitionObject2, RepetitionObject3, RepetitionObject4, RepetitionObject5],
}
},
methods: {
moveUp: function(key) {
var field = this.fields[0];
var value = field.value[key];
field.value[key] = field.value[key - 1];
field.value[key - 1] = value;
this.$set(this.fields, 0, field);
}
},
template: '#fieldset-template'
});
</script>
Whenever the moveUp method runs, it updates the fields object, but the field component doesn't re-render.
I have suspicion it is because of the secondary (outer) for cycle for the repetitions, but I couldn't figure a way around it.
this.$set(this.fields, 0, field);
won't do anything as this.fields[0]
is already equal to field
.
Assuming field.value
is an array, it's this step that's making a non-reactive change:
field.value[key] = field.value[key - 1];
field.value[key - 1] = value;
See https://v2.vuejs.org/v2/guide/list.html#Caveats
You could write it as:
this.$set(field.value, key, field.value[key - 1]);
this.$set(field.value, key - 1, value);
Or use splice
:
field.value.splice(key - 1, 2, field.value[key], field.value[key - 1]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With