vuejs2vue-dynamic-componentsasync-components

Vue2 create component based on data


I want to create a component based on ajax api response or data which include:

  1. template
  2. data
  3. methods - there may be several methods

Remark: response or data is dynamic and it is not saved in file.

I have tried to generate and return result like :

<script>
        Vue.component('test-component14', {
            template: '<div><input type="button" v-on:click="changeName" value="Click me 14" /><h1>{{msg}}</h1></div>',
            data: function () {
                return {
                    msg: "Test Componet 14 "
                }
            },
            methods: {
                changeName: function () {
                    this.msg = "mouse clicked 14";
                },
            }
        });

</script>

and do compile above code :

axios.get("/api/GetResult")
    .then(response => {
        comp1 = response.data;
        const compiled = Vue.compile(comp1);
        Vue.component('result-component', compiled);
    })
    .catch(error => console.log(error))

I got error on Vue.compile(comp1) -

  • Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as <script>, as they will not be parsed.

Thanks in advance


Solution

  • Your Api should return a JSON with every property required by a Vue component (name, data, template, methods), note that methods needs to be converted into an actual js function (check docs about that)

    Vue.config.productionTip = false;
    Vue.config.devtools = false;
    
    new Vue({
      el: '#app',
      data() {
        return {
          apiComponent: { template: '<div>Loading!</div>' }
        };
      },
      methods: {
        loadApiComponent() {
          setTimeout(() => {
            this.buildApiComponent(JSON.parse('{"name":"test-component14","template":"<div><input type=\\\"button\\\" v-on:click=\\\"changeName\\\" value=\\\"Click me 14\\\" /><h1>{{msg}}</h1></div>","data":{"msg":"Test Componet 14 "},"methods":[{"name":"changeName","body":"{this.msg = \\\"mouse clicked 14\\\";}"}]}'));
          }, 2000);
        },
        buildApiComponent(compObject) {
          const {
            name,
            template,
            data,
            methods
          } = compObject;
    
          const compiledTemplate = Vue.compile(template);
    
          this.apiComponent = {
            ...compiledTemplate,
            name,
            data() {
              return { ...data
              }
            },
            methods: methods.reduce((c, n) => {
              c[n.name] = new Function(n.body);
              return c;
            }, {})
          };
        }
      },
      mounted() {
        this.loadApiComponent();
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    
    <div id="app">
      <component :is="apiComponent" />
    </div>