Reputation: 10771
I have a parent
component that wraps multiple child
components. I want the parent component to manage the state of all its children. When the child is clicked I want the parent to know and I want to update all it's siblings so they know which one is active.
Vue.component('child', {
template: '#childtemplate',
props: ['index', 'activeIndex'],
methods: {
updateActiveIndex: function() {
console.log("emitting");
this.$emit('updateEvent', this.index);
}
}
});
Vue.component('parent', {
data: function() {
return {
activeIndex: 0
}
},
render: function(createElement) {
console.log("rendering ai->", this.activeIndex);
this.$options._renderChildren.forEach(function(item, index) {
if (item.data === undefined)
return;
item.componentOptions.propsData = {
index: index,
activeIndex: this.activeIndex
}
}.bind(this));
return createElement('div', {}, this.$options._renderChildren);
},
methods: {
handleToggle: function(index) {
this.activeIndex = index;
}
},
created: function() {
this.$on('updateEvent', this.handleToggle);
//try manually update it, but the children don't update.
setTimeout(function(){this.activeIndex = 6}.bind(this), 3000);
}
});
new Vue({
el: '#app'
})
I have tried adding event listener option to the createElement function in parent
render()
like so:
return createElement('div', {on:{updateEvent: this.handleToggle}}, this.$options._renderChildren);
I have tried setting an $on
listener in parent
created function. But this is not triggered.
I have tried manually updating activeIndex
with a timeout which updates it on the root, but children are not updated.
A hack solution and the only thing I've found to work is to reference a $parent
callback directly from the child passing up an index, then in the parent looping through the children and assigning the prop manually. This causes vue warn errors but gets the job done.
Is there a better way?
Upvotes: 1
Views: 3579
Reputation: 82439
I'm not sure this is better, but it works in this modified fiddle. Basically it iterates over the default slot, discards anything that isn't a child
, sets the appropriate properties and includes whatever is currently in each child's slot.
render: function(createElement) {
console.log("rendering ai->", this.activeIndex);
const children = [];
for (let i=0; i < this.$slots.default.length; i++){
if (!(this.$slots.default[i].tag == "child"))
continue;
children.push(createElement(Child, {
props:{
index: i,
activeIndex: this.activeIndex
},
on:{
updateEvent: this.handleToggle
}
}, this.$slots.default[i].children))
}
return createElement('div', {}, children);
}
Upvotes: 1