I have a series of components that go several levels deep. Each component has its own piece of data that it loads over AJAX and uses to render each instance of child components. The days
parent template for example:
<template>
<accordion :one-at-atime="true" type="info">
<panel :is-open="index === 0" type="primary" :header="'Day ' + day.day" v-for="(day, index) in days" :key="day.id">
<br/>
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">Cycles</h3>
</div>
<div class="panel-body">
<cycles
:day="day"
>
</cycles>
</div>
</div>
</panel>
</accordion>
</template>
The cycles
child template for example:
<template>
<accordion :one-at-atime="true" type="info">
<panel :is-open="index === 0" type="primary" :header="'Week ' + cycle.week + ': ' + cycle.name" v-for="(cycle, index) in cycles" :key="cycle.id">
<form v-on:submit.prevent="update">
....misc input fields here...
<button type="button" class="btn btn-warning" v-if="cycle.id" v-on:click="destroy">Delete</button>
</form>
</panel>
</accordion>
</template>
<script>
export default {
props: [
'day'
],
data() {
return {
cycles: []
}
},
beforeMount: function () {
var self = this;
if (this.cycles.length === 0) {
axios.get('/plans/days/' + this.day.id + '/cycles')
.then(function (response) {
self.cycles = response.data;
})
.catch(function (error) {
console.log(error);
});
}
},
methods: {
destroy: function (event) {
var self = this;
axios.delete('/plans/cycles/' + event.target.elements.id.value)
.then(function (response) {
self.cycles.filter(function (model) {
return model.id !== response.data.model.id;
});
})
.catch(function (error) {
console.log(error);
});
}
}
}
</script>
Each cycles
component then renders another component in a v-for
loop, which renders another type of component, and so on and so forth. What is created is a tree like structure of components.
When I need to send a generic request to the server that then updates the data in the component it is called from, I don't want to have to duplicate that request method in every component. I'd rather just have one instance of the method on the root Vue instance.
For example, this would be preferred:
const app = new Vue({
el: '#app',
store,
created: function () {
this.$on('destroy', function (event, type, model, model_id, parent_id) {
this.destroy(event, type, model, model_id, parent_id);
})
},
methods: {
destroy: function (event, type, model, model_id, parent_id) {
var self = this;
axios.delete('/plans/' + type + '/' + model_id)
.then(function (response) {
model = model.filter(function (model) {
return model.id !== response.data.model.id;
});
this.$emit('modified-' + type + '-' + parent_id, model);
})
.catch(function (error) {
console.log(error);
});
}
}
});
Then in the cycles.vue
delete button call this on click:
<button type="button" class="btn btn-warning" v-if="cycle.id" v-on:click="$root.$emit('destroy', event, 'cycles', cycles, cycle.id, day.id)">Delete</button>
And add this to cycles.vue
events:
created: function () {
this.$on('modified-cycles-' + this.day.id, function (cycles) {
this.cycles = cycles;
})
},
However, that doesn't work because the child element never gets the emitted 'modified-' + type + '-' + parent_id
event from root.
I also tried this.$children.$emit('modified-' + type + '-' + parent_id, model);
but that didn't work either.
What's the Vue 2.5.16 way to do this? And is there a better design pattern than I am currently using?
this
in the payload of theemit
? – Roy J