Vue: pass instantiated component to slot

I'm writing a component that renders a text. When a word starts with '@' it's a user's reference (like in twitter), and I must create a tooltip with the user's info.

This is how I instantiate the user's info component (this works fine, I'm using it in other places of the app):

    const AvatarCtor = Vue.extend(AvatarTooltip);
    let avatarComponent = new AvatarCtor({
      propsData: {
        user: user
      }
    });

This is the TooltipWrapper component:

<template>
  <el-tooltip>
    <slot name="content" slot="content"></slot>
    <span v-html="text"></span>
  </el-tooltip>
</template>

<script>
  import {Tooltip} from 'element-ui';

  export default {
    name: "TooltipWrapper",
    components: {
      'el-tooltip': Tooltip
    },
    props: {
      text: String
    }
  }
</script>

And this is how I wire it up all together:

const TooltipCtor = Vue.extend(TooltipWrapper);
const tooltip = new TooltipCtor({
    propsData: {
        text: "whatever"
    }
});
tooltip.$slots.content = [avatarComponent];
tooltip.$mount(link);

This doesn't work. But if I set some random text in the content slot, it works fine:

tooltip.$slots.content = ['some text'];

So my problem is that I don't know how to pass a component to the slot. What am I doing wrong?

Upvotes: 1

Views: 2473

Answers (1)

Sphinx
Sphinx

Reputation: 10729

this.$slots is VNodes, but you assign with one component instance.

Below is one approach (mount the component to one element then reference its vnode) to reach the goal.

Vue.config.productionTip = false
const parentComponent = Vue.component('parent', {
  template: `<div>
  <div>
    <slot name="content"></slot>
    <span v-html="text"></span>
  </div>
</div>`,
  props: {
    text: {
      type: String,
      default: ''
    },
  }
})

const childComponent = Vue.component('child', {
  template: `<div>
  <button @click="printSomething()">@<span>{{user}}</span></button>
  <h4>You Already @ {{this.clickCount}} times!!!</h4>
</div>`,
  props: {
    user: {
      type: String,
      default: ''
    },
  },
  data(){
    return {
      clickCount: 1
    }
  },
  methods: {
    printSomething: function () {
      console.log(`already @${this.user} ${this.clickCount} times` )
      this.clickCount ++
    }
  }
})

const TooltipCtor = Vue.extend(parentComponent)
const tooltip = new TooltipCtor({
  propsData: {
    text: "whatever"
  }
})
const SlotContainer = Vue.extend(childComponent)
const slotInstance = new SlotContainer({
  propsData: {
    user: "one user"
  }
})
slotInstance.$mount('#slot')
tooltip.$slots.content = slotInstance._vnode
tooltip.$mount('#link')
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="link">
</div>
<div style="display:none"><div id="slot"></div></div>

Upvotes: 1

Related Questions