Leon
Leon

Reputation: 2149

How can I duplicate slots within a Vuejs render function?

I have a component which is passed content via a slot. I'm using a render function to output the content. The reason I'm using a render function is because I want to duplicate the content multiple times. When I use this code, everything works fine:

render(createElement){
    return createElement('div', {}, this.$slots.default);
}

When I data that is being passed changes, the output changes as well.

However, since I want to duplicate the slot content, I'm now trying this:

return createElement(
    'div', {},
        [
            createElement('div', { }, this.$slots.default),
            createElement('div', { }, this.$slots.default)
        ]
    )

Now the problem is, when the slot content changes from outside the component, only the content in the second div gets updated, the content in the first div stays the same..

Am I missing something here?

Upvotes: 5

Views: 4170

Answers (2)

Remigius Stalder
Remigius Stalder

Reputation: 2170

I found this SO question searching for a way to render the content of a slot multiple times like e.g. for a generic list that can have a template for the content of a list row, which is used for each item.

As of 2020 (in fact earlier) multiple rendering of a slot can be achieved using scoped slots. This is documented here:

https://v2.vuejs.org/v2/guide/components-slots.html#Other-Examples

The documentation says:

Slot props allow us to turn slots into reusable templates that can render different content based on input props

(obviously, if we can use the template to render different content based on props, we can also use it to render the same content)

The example given right there uses a template instead of a render function, but how to use scoped slots in a render function is fortunately also documented:

https://v2.vuejs.org/v2/guide/render-function.html#Slots

Upvotes: 1

Jacob Goh
Jacob Goh

Reputation: 20845

I can't explain why it happens. But the doc does mention that "VNodes Must Be Unique" in a render function. See https://v2.vuejs.org/v2/guide/render-function.html#Constraints.

Anyway, this is a VNode cloning function, which works, which I discovered from https://jingsam.github.io/2017/03/08/vnode-deep-clone.html.

function deepClone(vnodes, createElement) {
    function cloneVNode(vnode) {
        const clonedChildren = vnode.children && vnode
            .children
            .map(vnode => cloneVNode(vnode));
        const cloned = createElement(vnode.tag, vnode.data, clonedChildren);
        cloned.text = vnode.text;
        cloned.isComment = vnode.isComment;
        cloned.componentOptions = vnode.componentOptions;
        cloned.elm = vnode.elm;
        cloned.context = vnode.context;
        cloned.ns = vnode.ns;
        cloned.isStatic = vnode.isStatic;
        cloned.key = vnode.key;
        return cloned;
    }
    const clonedVNodes = vnodes.map(vnode => cloneVNode(vnode))
    return clonedVNodes;
}

How to use it:

render(createElement) {
    return createElement('div', {}, [
        createElement('div', {}, this.$slots.default),
        createElement('div', {}, [...deepClone(this.$slots.default, createElement)])
    ])
}

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

Upvotes: 3

Related Questions