3

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> 
2
  • Why do that when you could just have your step1-state and step2-state components use the modal directly and then just use a div or something as the wrapper in wizard? Commented Jul 31, 2017 at 13:27
  • @lamelemon This is what I ended up doing, but the question still stands. In my opinion this is possible use case. Commented Jul 31, 2017 at 13:36

2 Answers 2

1

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> 
Sign up to request clarification or add additional context in comments.

1 Comment

Couold you give a full example of this in codepen?
0

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 ))

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.