2

I want to render some forms and bind them to Vue. forms are listed on json Like this.

formslist:[
    "<input type='text' name='item1' v-model='item1'>",
    "<input type='text' name='item2' v-model='item2'>",
]

I could render them but couldn't bind. Template is this.

<div v-for="form in formslist">
    <div v-html="form"></div>
</div>

Later, I understood that html added by "v-html" can't use data bindings. But then I don't have no ideas how to do this. Would anyone teach me good solution?


Sorry for lack of words. I wrote code like this but "item1" and "item2" are not binded.

js:

new Vue({
  el: '#app',
  data() {
    return {
      formData: {},
      formslist:
        // this list is got by ajax as neccessary
        {
            "item1": "<input type='text' name='item1' v-model='formData.item1'>",
            "item2": "<input type='text' name='item2' v-model='formData.item2'>",
        }
    };
  },
  methods: {
    submit() {
      alert('formdata: ' +  JSON.stringify(this.formData));

      // submit data to backend
      // e.g. axios.post(...).then(...).catch(...);
    }
  }
})

html:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app">
  <form name="myForm" @submit.prevent="submit">
    <div class="form-group">
      <label>Firstname</label>
      <input class="form-control" v-model="formData.firstName" type="text">
    </div>
    <div class="form-group">
      <label>Lastname</label>
      <input class="form-control" v-model="formData.lastName" type="text">
    </div>
    <div class="form-group">
      <label>Description</label>
      <textarea class="form-control" v-model="formData.description"></textarea>
    </div>

    <div class="form-group" v-for="(form, name) in formslist">
      <label>{{name}}</label>
      <div v-html="form"></div>
    </div>

    <button type="submit">
      Submit
    </button>
  </form>
</div>

1 Answer 1

1

Vue.js is model/data oriented - have a look at the docs to learn more about it.

So create a model where you're storing your form data and then use that model to submit the data or do anything you like with the data.

Please have a look at a basic example below or at this fiddle.

Update 01.07.2017

OK, now I understand what you're trying to do. Please find my updated code below or at the fiddle (same link).

You could also use a form generator like vue-form-generator. It's doing the same as my demo - just fewer coding required.

How does it work?

The form will be rendered with a template that is getting the data from a model that you can get from the server.

The type of the input can't be bound with :type because that's not supported with v-model - there was an error message when I tried that. So it's a bit more to write but it should be clear how this works. Add similar template tags for other types.

To further improve the model, you could also store the top-level of your form, so you can customize that display class as well. e.g. something like:

{
  formName: 'myForm',
  className: 'form-horizontal',
  items: [...] // same array as before
}

If you need to group some inputs or display them differently you can add more properties to the model and more logic to the template.

const formRenderModel = [{
  type: 'text',
  modelName: 'firstName',
  className: 'form-control',
  labelText: 'First name',
  required: true
}, {
  type: 'text',
  modelName: 'lastName',
  className: 'form-control',
  labelText: 'Last name',
  required: true
}, {
  type: 'text',
  modelName: 'description',
  className: 'form-control',
  labelText: 'Description',
  required: true,
  pattern: '.{10,}', // minimum 10 characters
  validationMessage: 'Minimum 10 characters required'
}];

new Vue({
  el: '#app',
  data() {
    return {
      formData: {}
    };
  },
  created() {
    // later axios.get('/form-render).then(...).catch(...);
    // now just a constant
    this.formRenderModel = formRenderModel;
  },
  methods: {
    submit() {
      console.log('formdata', this.formData);

      // submit data to backend
      // e.g. axios.post(...).then(...).catch(...);
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app">
  <form name="myForm" @submit.prevent="submit">
    <div v-for="inputModel in formRenderModel">
      <label>{{inputModel.labelText}}</label>
      <template v-if="inputModel.type == 'text'">
        <input type="text" v-model="formData[inputModel.modelName]"     
          :class="inputModel.className" 
          :pattern="inputModel.pattern"  
          :title="inputModel.validationMessage"
          :required="inputModel.required" />
      </template>
      <!-- add more templates for radios, checkboxes, .. -->
    </div>
    <button type="submit">
      Submit
    </button>
  </form>
</div>

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

3 Comments

Thanks for your fast and clearly answer AWolf. But I know the general usage of vue.js. Sorry for lack of words. I added the code with reference to your code, so would you see it again?
So you'd like to render the form dynamically depending on the data that you're getting with an ajax request, right? I wouldn't add html for this into your ajax data. I would add a json representation of your form and render the form according to that data. I'll update my answer and edit the demo later today.
Yes,that's it. I'm waiting for you!

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.