lucas
lucas

Reputation: 75

Add dynamically data-bound text in Vue.js

My case must be weird, but I have a good for it. Here's my situation:

I have a Vue app that renders a form based on a json. For example, the JSON:

{
  "fields": [{
      "name": "firstName",
      "title": "Name"
  }, {
      "name": "lastName",
      "title": "Last Name"
  }, {
      "title": "Hello {{ firstName }}!"
  }]
}

From that json, the final render has to be:

<input type="text" name="firstName" v-model="firstName" />
<input type="text" name="lastName" v-model="lastName" />
<p>Hello {{ firstName }}</p>

I'm able to render all of that, except for the <p> which is rendered as raw {{ firstName }} and not data-bound/reactive.

My question is: How do I insert dynamic templates (can come from a Rest API) into the component, and make them have the full power of the mustache expressions.

The component will have something like

{...firstName field...}
<dynamic template will be added here and update whenever firstName changes>

Please let me know if I'm not too clear on this issue Thank you!!!

Upvotes: 1

Views: 7018

Answers (1)

Roy J
Roy J

Reputation: 43881

Is this the sort of thing you're trying to do? I've created a dynamic component whose template is generated from a JSON string which is editable.

new Vue({
  el: '#app',
  data: {
    componentData: {
      firstName: 'Jason',
      lastName: 'Bourne',
    },
    jsonString: `
    {
      "fields": [{
        "name": "firstName",
        "title": "Name"
      }, {
        "name": "lastName",
        "title": "Last Name"
      }, {
        "title": "Hello {{ firstName }}!"
      }]
    }`
  },
  computed: {
    template() {
      const json = JSON.parse(this.jsonString);

      return json.fields.map((s) => {
        if ('name' in s) {
          return `<input type="text" name="${s.name}" v-model="${s.name}">`;
        }
        return s.title;
      }).join('\n');
    },
    componentSpec() {
      return {
        template: `<div>${this.template}</div>`,
        data: () => this.componentData
      };
    }
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <textarea rows="16" cols="40" v-model.lazy="jsonString">
  </textarea>
  <component :is="componentSpec"></component>
</div>

Upvotes: 7

Related Questions