DengSihan
DengSihan

Reputation: 2997

Vuejs how to use dynamical template in component?

const CustomComponent = {
  props: ['index'],
  template: `<span>I am a custom component: {{ index }}</span>`
};

const UserInputResult = {
  components: {
    CustomComponent
  },
  props: ['templateString'],
  template: `<section v-html="templateString"></section>` 
}

const app = new Vue({
   el: '#app',
   data(){
      return {
         userInput: 'user input example [:component-1]'
      }
   },
   components: {
      UserInputResult
   },
   methods: {
      generateTemplate(){
         let raw = this.userInput;
         if (!!raw && raw.match(/\[\:component\-\d+\]/g)) {
            let components = [...raw.match(/\[\:component\-\d+\]/g)];
            components.forEach(component => {
               raw = raw.replace(component, `<custom-component :index="${component.match(/\d+/)[0]}"></custom-component>`);
            });             
         }
         return raw;
      }
   }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
  <textarea v-model="userInput"></textarea>
  <user-input-result :template-string="generateTemplate()">
</div>

I want to render a custom component which has a dynamical template base on user input.

when user input a specific string ([:component-1]), it will be render as a component (CustomComponent)

how to achieve this?

Thanks a lot for anyone help!

Upvotes: 0

Views: 187

Answers (2)

Cerceis
Cerceis

Reputation: 860

You should look into v-slot
https://v2.vuejs.org/v2/guide/components-slots.html

Example:
Parent:

<child-component v-html="myTemplate">
    <span>From parent</span>
</child-component>

Child:

<div>
    <v-slot></v-slot> //Will output "<span>From parent</span>"
</div>

**Added more explaination
You can then condition check and update myTemplate to your desired template. "<span>From parent</span>" is just there for explanation on how slot works.


updated by the questioner

const CustomComponent = {
  props: ['index'],
  template: `<span>I am a custom component: {{ index }}</span>`
};

const UserInputResult = {
  template: `<section><slot></slot></section>` 
}

const app = new Vue({
   el: '#app',
   data(){
      return {
         userInput: 'user input example [:component-1]'
      }
   },
   components: {
      UserInputResult,
      CustomComponent
   },
   methods: {
      generateTemplate(){
         let raw = this.userInput;
         if (!!raw && raw.match(/\[\:component\-\d+\]/g)) {
            let components = [...raw.match(/\[\:component\-\d+\]/g)];
            components.forEach(component => {
               raw = raw.replace(component, `<custom-component :index="${component.match(/\d+/)[0]}"></custom-component>`);
            });             
         }
         return raw;
      }
   }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
  <textarea v-model="userInput"></textarea>
  <user-input-result>
    {{ generateTemplate() }} 
  </user-input-result>
</div>

Upvotes: 1

DengSihan
DengSihan

Reputation: 2997

I figured it out by using Vue.complie

according to dynamically-fetch-and-compile-a-template-with-nuxt

const UserInputResult = {
  props: ['templateString'],
  render(h){
    return h({
      components: {
        CustomComponent
      },
      template: `<section>${this.templateString}</section>`
    });
  }
}

Upvotes: 0

Related Questions