Reputation: 1747
I've got a modal component that looks like this
//modal component
<template>
<slot></slot>
<slot name='buttons'></slot>
</template>
I want to use it as a wizard
//wizard component
<template>
<modal>
<step1-state v-if='step === 1'/>
<step2-state v-if='step === 2'/>
</modal>
</template>
Is there a way that step1,step2,etc consume buttons
slot?
This does not seem to work
//step1-state component
<template>
<div>
<span>Does it work?</span>
<div slot='buttons'>
<button>yes</button>
<button>no</button>
</div>
</div>
</template>
Upvotes: 3
Views: 3227
Reputation: 1747
After some research I found that this is not possible by default. I was able to achieve this using custom render functions.
child-slot
component - this one needs to be placed inside parent slot content, it enables you to format content of child component. You can add more than one child-slot
to mix it with parent content. It needs to define ref
attribute with distinct value.
use-slot
component - this one is used to tell what content should be passed to parent as child-slot
content. Content will be placed inside span
element.
It needs named
and container
attributes.
named
- name of slot to place content in
container
- ref
value of child-slot
use-slot
will automatically find first parent slot named by named
attribute regardless of child depth
child-slot
<script>
export default {
render(createElement) {
return createElement('span', {}, this.content);
},
data() {
return {
nodesToRender: {}
}
},
computed: {
content() {
var result = [];
for (var node in this.nodesToRender) {
result = result.concat(this.nodesToRender[node] || []);
}
return result;
}
}
}
</script>
use-slot
<script>
export default {
abstract: true,
props: {
named: {
type: String,
required: true
},
container: {
type: String,
required: true
}
},
render() {
var parent = this.findParentOfSlot();
var content = this.$slots.default;
var self = this;
this.$parent.$nextTick(function () {
if (parent && parent.$refs && parent.$refs[self.container], parent.$refs[self.container].nodesToRender) {
Vue.set(parent.$refs[self.container].nodesToRender, self.$vnode.tag, content);
}
});
},
methods: {
findParentOfSlot() {
var parent = this.$parent;
while (parent) {
if (parent.$slots && parent.$slots[this.named]) {
return parent.$parent;
}
parent = parent.$parent;
}
return parent;
}
}
}
</script>
Upvotes: 1
Reputation: 1752
As far as I know, this is not possible currently and doesn't make too much sense because it becomes complicated and hard to read. Imagine looking at such nested slot code after 3 months of writing it. If both your step components require this buttons
slot then write it as a sibling near them and send props whenever you have changes from this buttons
slot
By the way, there seems to be a wizard component out there https://github.com/cristijora/vue-form-wizard , accidentally written by myself ))
Upvotes: 0