I am struggling to get my head around the process of encapsulating reusable elements within a component but still allowing parental interference of the data within it.
In my current case I have a form stepper/wizard and within that, I have child form-tab components. The navigation buttons live in the form-wizard component.
I have a top-level component in my app that hosts a form-wizard and I want to delegate the task of validating steps of the form to the host/parent component. I do not want a navigation button enabled until the host/parent is satisfied that the current and previous steps are valid. I've put together an example:
Vue.component("form-tab", {
template: '<div v-show="isActive"><slot></slot></div>',
props: {
title: '',
selected: {
default: false
}
},
data() {
return {
isActive: false,
isValid: false
}
},
created() {
this.isActive = this.selected
}
});
Vue.component('form-wizard', {
template: '#form-wizard-template',
props: ["form_data"],
data() {
return {
activeStepIndex: 0,
maxStep: 0,
loading: false,
tabs: []
}
},
computed: {
totalTabs() {
return this.tabs.length;
},
},
created() {
this.tabs = this.$children;
},
mounted() {
},
methods: {
progress() {
},
previousTab() {
this.activeStepIndex--;
this.tabs.forEach(tab => {
tab.isActive = false;
});
this.tabs[this.activeStepIndex].isActive = true;
setTimeout(() => {
this.progress()
});
},
nextTab() {
this.scrollToTop();
this.activeStepIndex++;
this.tabs.forEach(tab => {
tab.isActive = false;
});
this.tabs[this.activeStepIndex].isActive = true;
setTimeout(() => {
this.progress()
});
this.maxStep = this.activeStepIndex
},
jumpToTab(i) {
// Only allow a jump to previous steps
if(i <= this.maxStep && this.maxStep < this.tabs.length - 1) {
this.activeStepIndex = i;
this.tabs.forEach(tab => {
tab.isActive = false;
});
this.tabs[i].isActive = true;
setTimeout(() => {
this.progress()
});
}
},
scrollToTop() {
var top = $(window).width() >= 576 ? this.$el.offsetTop - $('header').height() : this.$el.offsetTop;
window.scrollTo(0, top - 50);
},
submitform() {
this.$emit("submit", this.form_data);
},
validatetab() {
this.tabs[this.activeStepIndex].isValid = this.$emit("validatetab", this.activeStepIndex);
}
}
})
Vue.component("myform", {
template: '#myform-template',
data() {
return {
form_data: {
name: 'Example'
}
}
},
methods: {
submit(form_data) {
alert('Form submitted');
},
validateTab(index) {
return confirm('Validating Tab ' + index);
}
}
});
new Vue({
el: "#app",
data() {
return{};
}
})
https://jsfiddle.net/ProNotion/gnj8uzpa/
It seems to me that this.$emit
is a one way road and no return value passes back to the child?