Kirill
Kirill

Reputation: 534

Vue pass slot template to extended component

Is any way to pass a template to extended component? Example, that illustrates the problem:

There is a component named Slide with a template like so:

<template>
    <div class="swiper-slide swiper-slide-one">
        <div class="swiper-filter"></div>
        <slot />
    </div>
</template>

In other place i need to create and mount that component in imperative style:

import SlideComponent from '@/components/Slide'
const Slide = Vue.extend(SlideComponent);
new Slide().$mount('#container');

The problem is that i have no idea how to pass a template that will be compiled in the slot of the extended component.

jsfiddle

Upvotes: 10

Views: 7564

Answers (5)

Bert
Bert

Reputation: 82459

You can use Vue.compile combined with $createElement.

const slotTemplate = `<div><h4>This is the slot content</h4>{{message}}</div>`;
const renderer = Vue.compile(slotTemplate)
const slotContent = {
  data(){
    return {
      message: "some data in the slot"
    }
  },
  render: renderer.render,
  staticRenderFns: renderer.staticRenderFns
}

const instance = new Slide();
instance.$slots.default = [instance.$createElement(slotContent)];
instance.$mount("#container");

Above is an example of a slot that requires some data. If your slot content is just HTML you could get away with just this:

const slotTemplate = `<div><h4>This is the slot content</h4></div>`
const instance = new Slide();
instance.$slots.default = [instance.$createElement(Vue.compile(slotTemplate))];
instance.$mount("#container");

Here is an example.

Note: $slots[key] should be an array of vNodes. It will render correctly if you use a vNode, but there will be bugs (e.g. when calling vm._update)

Upvotes: 5

Sykur
Sykur

Reputation: 3

If You can change Your source code structure, You should also be able to use jsx. In Vue-Cli3 it requires additional babel plugin, in Nuxt it works out of the box). You simply create some hook function as method or compute, for example:

slotHook () {
  return(
  <template v-slot.../>
)}

and place it inside the render function. Then, in the child (component extending the default one), You overwrite the slotHook method:

slotHook () {
  return (
    <template v-slot... some-differen-params:.../>
)}

This approach does not cause any errors/issues during render and works flawless. Other approach might be to use PUG templates and their block & extend functionality. I know I'm posting this response quite late, but maybe it could help somebody.

Upvotes: 0

Jacob Goh
Jacob Goh

Reputation: 20855

(This question is similar to this SO question. I am just gonna share a similar answer I post for that question here.)

The trick is simple. Basically, when extending, create a new component that registers Parent as a local component.

Demo: https://jsfiddle.net/jacobgoh101/omjgmb3f/

const Slide = Vue.extend({
  components: {
    Parent
  },
  template: `
  <Parent>
    <div style="color:red">I am a slot</div>
  </Parent>
`
});
new Slide().$mount('#container')

Upvotes: 1

Jonatas Walker
Jonatas Walker

Reputation: 14150

If you are open to change your approach a little bit, a <component> instead of <slot>:

https://jsfiddle.net/jonataswalker/z5Lgbjv8/

const Parent = {
  template: `<div>
        <span>parent content</span>
      <component :is="view"></component>
    </div>`,
  data() {
    return { view: '' }
  }
}

const Other = {
  template: `<div>
        <h1>from Other</h1>
    </div>`
}

const Slide = Vue.extend(Parent)

// how to pass template to the Parent`s slot?
new Slide({
  data: { view: Other }
}).$mount('#container')

Upvotes: 1

Saurabh
Saurabh

Reputation: 73609

You have to pass it like this:

<Slide>
   //HTML code here goes to slot
</Slide>

Upvotes: -2

Related Questions