0

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 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks! This does exactly what I want. You say you are not sure of this solution, could you elaborate a bit on what might make it a bad solution?
I see a problem. On the custom-table component I have a computed function. When I try to call that one from the x-template I get that it could not be found. Can it be referenced somehow?
@Martin Yes, you'd need to pass it through to the child component via a prop: template: `<component :is="{ template: '#' + template, props: ['propertyName'] }" :propertyName="propertyName" />` , or as data: template: `<component :is="{ template: '#' + template, data: { propertyName } }" />` . Here propertyName is the name of your computed property.
@Martin My main concern would be around performance, as it not only requires a full Vue build but also it has to do a lot of extra template compilation. I would also worry about such an unconventional use of Vue... as you're already discovering with the computed property problem there are likely to be unforeseen pitfalls straying this far off the usual path. You didn't provide any background as to why you want to use dynamic x-templates but it seems likely that there'd be a better way to approach the underlying problem than this.
1

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.

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.