Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create Vue.js slot programmatically?

Tags:

I have the following component with a slot:

<template>
    <div>
        <h2>{{ someProp }}</h2>
        <slot></slot>
    </div>
</template>

For some reasons, I have to manually instantiate this component. This is how I am doing it:

const Constr = Vue.extend(MyComponent);
const instance = new Constr({
    propsData: { someProp: 'My Heading' }
}).$mount(body);

The problem is: I am not able to create slot contents programmatically. So far, I can create simple string based slot:

const Constr = Vue.extend(MyComponent);
const instance = new Constr({
    propsData: { someProp: 'My Heading' }
});

// Creating simple slot
instance.$slots.default = ['Hello'];

instance.$mount(body);

The question is - how can I create $slots programmatically and pass it to the instance I am creating using new?

Note: I am not using a full build of Vue.js (runtime only). So I don't have a Vue.js compiler available to compile the template on the fly.

like image 252
Harshal Patil Avatar asked May 03 '18 08:05

Harshal Patil


People also ask

How do you make your own slots at Vue?

Also note that the fallback text of “Text In Slots Example” is replaced entirely. So in the most basic sense when you want to use slots in VueJS, you add the <slot></slot> tags in the child component where you expect to receive data from outside.

How do I use Vue JS slots?

How to use it. Using the slot is very easy, we should just write the <slot> component (which is a reserved word in Vue. js) inside the child component's template, where we want to receive data. A child component uses slot.

What is V slot in VUE JS?

Vue slots syntax with v-slot directive With new v-slot directive, we can: – combine html layers: component tag and scope of the slot. – combine the slot and the scoped slot in a single directive.

What is V slot activator?

Details on the activator slotVMenu allows users to specify a slotted template named activator , containing component(s) that activate/open the menu upon certain events (e.g., click ).


2 Answers

I looked into TypeScript definition files of Vue.js and I found an undocumented function on Vue component instance: $createElement(). My guess is, it is the same function that is passed to render(createElement) function of the component. So, I am able to solve it as:

const Constr = Vue.extend(MyComponent);
const instance = new Constr({
    propsData: { someProp: 'My Heading' }
});

// Creating simple slot
const node = instance.$createElement('div', ['Hello']);
instance.$slots.default = [node];

instance.$mount(body);

But this is clearly undocumented and hence questionable approach. I will not mark it answered if there is some better approach available.

like image 109
Harshal Patil Avatar answered Sep 20 '22 14:09

Harshal Patil


I think I have finally stumbled on a way to programmatically create a slot element. From what I can tell, the approach does not seem to work for functional components. I am not sure why.

If you are implementing your own render method for a component, you can programmatically create slots that you pass to child elements using the createElement method (or whatever you have aliased it to in the render method), and passing a data hash that includes { slot: NAME_OF_YOUR_SLOT } followed by the array of children within that slot.

For example:

Vue.config.productionTip = false
Vue.config.devtools = false;

Vue.component('parent', {
  render (createElement) {
    return createElement('child', [
      createElement('h1', { slot: 'parent-slot' }, 'Parent-provided Named Slot'),
      createElement('h2', { slot: 'default' }, 'Parent-provided Default Slot')
    ])
  }
})

Vue.component('child', {
  template: '<div><slot name="parent-slot" /><slot /></div>'
})

new Vue({
  el: '#app',
  template: '<parent />'
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

<div id='app'>
</div>
like image 41
Andrew H Avatar answered Sep 20 '22 14:09

Andrew H