0
votes

I have this component, and would like to pass a parameter/prop to the component saying which x-template to use. When I do it like this, it fails:

JS:

Vue.component('custom-table', {
    props: ['template'],
    template: '#' + this.template
})
new Vue({ el: '#app' })

HTML:

<custom-table template="my-template"></custom-table>

<script type="text/x-template" id="my-template">
   <p>My Template</p>
</script>

Error:

vue.js:3 [Vue warn]: Cannot find element: #undefined

How can I use dynamic templates like this?

2

2 Answers

2
votes

I'm not sure whether this is actually a good idea but it does come pretty close to what you've requested:

Vue.component('custom-table', {
  props: ['template'],
  template: `<component :is="{ template: '#' + template }" />`
})

new Vue({
  el: '#app'
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<script type="text/x-template" id="button-template">
   <button>My Template</button>
</script>

<script type="text/x-template" id="em-template">
   <em>My Template</em>
</script>

<div id="app">
  <custom-table template="button-template"></custom-table>
  <custom-table template="em-template"></custom-table>
</div>

The trick here is to use the object version of is, which allows you to pass in a component definition inline. Strictly speaking there are two components in play here, a parent and a child, and the x-template is assigned to the child. That said, the resulting DOM should be as desired as the parent doesn't add any extra elements of its own.

1
votes

You can't have dynamic templates for a single component.

You could create various components, and then dynamically pick which component to render for the particular tag. For this, Vue supports dynamic component:

<component v-bind:is="currentTabComponentName"></component>

Alternatively, if you want caller to fill-in-the-blanks of your component with arbitrary HTML, then you can use slots.

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

Or, if it is just static HTML, then you can just pass the HTML itself as string, and render the content without escaping it:

<div v-html="task.html_content"> </div>

Maybe one of these works for you...

Other options could be to use render functions or JSX.