I like mohghaderi's answer, but I ran into several issues with it, so I will use his sample code to show the changes I needed to make in order for it work. (In my own project, I'm using Vue 3 and the Options API.)
mohghaderi's Parent Component code with notes about my changes:
import ChildComponent from './components/ChildComponent'
new Vue({
el: '#app',
data: {
item: {},
childMethodsQueue: [],
},
// Note: In the template below, I added @child-methods-finished="childMethodsFinished"
// as an event listener, so that we can reset the childMethodsQueue array to
// empty once the methods are finished.
// If you don't reset it, then the methods stay in there and cause problems.
template: `
<div>
<ChildComponent :item="item"
:methods-queue="childMethodsQueue"
@child-methods-finished="childMethodsFinished" />
<button type="submit" @click.prevent="submit">Post</button>
</div>
`,
methods: {
submit() {
this.childMethodsQueue.push({
name: ChildComponent.methods.save.name,
params: {} // Note: delete the {} and put the name of your params, if you use a method that passes in params.
})
}
},
components: { ChildComponent },
})
mohghaderi's Child Component code with notes about my changes:
import { objectToString } from "@vue/shared"
export default {
name: 'ChildComponent',
props: {
methodsQueue: { type: Array },
},
// Note: I had to rewrite the watch option because it would not trigger.
// You have to add "deep, true" for arrays and objects.
// The function has to be called "handler" for it to work as well.
watch: {
methodsQueue: {
handler() {
this.processMethodsQueue()
},
deep: true,
}
},
// Note: Remove "mounted()" function if you don't want it to run on the mounted event.
mounted() {
this.processMethodsQueue()
},
methods: {
save() {
console.log("Child saved...")
},
processMethodsQueue() {
if (!this.methodsQueue) return
let len = this.methodsQueue.length
if (!len) return // Note: This is required to prevent an infinite loop.
// When we reset the childMethodsQueue array to empty,
// it will trigger this method through the watch option,
// so we need this in order to stop the cycle once we are done.
// Note: Instead of using ".shift()" to access an item in the array
// we need to use "[i]" otherwise we will get muliple calls of the method
for (let i = 0; i < len; i++) {
let method = this.methodsQueue[i]
this[method.name](method.params)
}
// Note: Now that we are done calling methods, we need to emit an event back to the parent
// so it can call it's method to reset the childMethodsQueue array to empty
this.$emit('child-methods-finished')
},
},
}