jla
jla

Reputation: 4790

Use dynamic Vue components in render function

I have a Vue single page app which needs to be updated with different components. The components used should be able to be changed at any time by the user.

In my attempt to achieve this I created an object that, for each key, returns a Vue component corresponding to the type required. This way, if I had the name of an required component (and some data for it) I could get the component by calling myComponents[name](data).

myComponents = {
    heading: ( data ) => Vue.component( 'heading', {
        ... // use data
        render: function() {
            ...
        }
    } ),
    content: ( data ) => Vue.component( 'content', {
        ...
    } )
    // and more of the same
}

In my main app I used a data object that contained the component keys needed, and a render function that mapped those keys to the object, receiving the necessary component. Updating the data object should update the components mapped onto the page.

var page = new Vue( {
    el: '#page',
    data: function() {
        return {
            page_content: [ { type: 'heading', data: 'lorem ipsum' },
                            { type: 'content', data: 'more lorem ipsum' } ]
        }
    },
    render: function( h ) {
        return h( 'div',
            { attrs: { id: 'page' } },
            this.page_content.map( p => myComponents[ p.type ]( p.data ) )
        )
    }
} )

The problem is that the main render function does not add components. The element is left blank. Why is this the case?

This is a fairly simple app so I'd like to continue using render functions rather than templates.

Upvotes: 2

Views: 2058

Answers (1)

jla
jla

Reputation: 4790

The answer was embarrassingly simple.

I was forgetting to create an element from the returned component and was simply putting the raw Vue component directly in the content array.

My main render function should have been:

render: function( h ) {
    return h( 'div',
        { attrs: { id: 'page' } },
        this.page_content.map( p => h( myComponents[ p.type ]( p.data ) ) )
    )
}

Upvotes: 2

Related Questions