1

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!!!

6
  • You could make your json a computed property and have "title": "Hello " + this.firstName Commented Nov 28, 2018 at 15:00
  • Yeah i was able to do it, but that didnt seem elegant to me.I had to end up using sending a JS string concatenation expression in the JSON via REST API, so it ended up with something like { "title": { "'Hello ' + this.firstName } } and call an eval() on that in a computed property. But again, not elegant... I'll wait for better approach as I can't find one Commented Nov 28, 2018 at 15:11
  • mmm yeah calling eval is a code smell. Hard to give advice without seeing your full code though. Commented Nov 28, 2018 at 15:29
  • <p>Hello <span v-text="firstName"></span></p>? Commented Nov 28, 2018 at 15:32
  • Can't use that because the entire new element <p>Hello <span v-text="firstName"></span></p> is a string to be set in an element. This element does not exist up until something the response is retrieve from the API, and that changes all the time. One string may be reading the firstName, but another may be reading anything else Commented Nov 28, 2018 at 15:37

1 Answer 1

7

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>

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

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.