Edit in JSFiddle

Vue.component('form-input', {
  props: ['question'],
  template: '<div class="form-group" :class="{\'input\': true, \'has-error\': errors.has(question.label) }">' +
    '<input type="text" v-validate="question.validate" :id="question.id" :name="question.label"'+
           'class="form-control" v-model="question.answer":placeholder="question.placeholder"/>' +
    '    <span v-show="errors.has(question.label)" class="help-block">{{ errors.first(question.label) }}</span>' +
    '</div>'
});

Vue.component('form-select', {
    props: ['question'],
    created: function () {
        this.$options.template = '<div class="form-group" :class="{\'input\': true, \'has-error\': errors.has(question.label) }">' +
        '<select v-validate="question.validate" :id="question.id" :name="question.label" v-model="question.answer" class="form-control" >' +
        '<option v-for="option in question.options" >{{option}}</option>' +
        '</select>' +
        '<span v-show="errors.has(question.label)" class="help-block">{{ errors.first(question.label) }}</span>' +
        '</div>'
    }
});

Vue.component('form-radio', {
  props: ['question'],
  created: function() {
    this.$options.template = '<div class="col-sm-9"> ' +
      '<label  v-for="option in question.options" :for="option" class="radio-inline" >' +
      '<input :id="option" :name="question.label" type="radio" v-model="question.answer"' +
      '       :value="option"/> {{option}}' +
      '</label>' +
      '</div>';
  }
});

Vue.component('form-textarea', {
  props: ['question'],
  template: '<textarea v-validate="question.validate" class="form-control" placeholder="" v-model="question.answer"  :placeholder="question.placeholder"/>'
});

Vue.component('form-question', {
  props: ['question'],
  created: function() {
    this.$options.template = '<div class="form-group"> ' +
      '<label for="" class="col-sm-3 col-lg-2 control-label">' +
      '{{question.label}}';
    if ((this.question.validate !== undefined) && this.question.validate.match("required")) {
      this.$options.template += '<em>*</em>'
    }
    this.$options.template += '</label>' +
      '<div class="col-sm-9 col-lg-10">';
    switch (this.question.type) {
      case 'input':
        this.$options.template += '<form-input :question="question"></form-input>';
        break;
      case 'select':
        this.$options.template += '<form-select :question="question"></form-select>';
        break;
      case 'radio':
        this.$options.template += '<form-radio :question="question"></form-radio>';
        break;
      case 'textarea':
        this.$options.template += '<form-textarea :question="question"></form-textarea>';
        break;
      default:
        this.$options.template += 'Unsupported question type: ' + this.question.type;
    }
    this.$options.template += '</div></div>';
  }
});

Vue.use(VeeValidate);

// bootstrap the application
var app = new Vue({
  el: '#dynform',
  data: {
    questions: []
  },
  created: function() {
    // Dynamic Form could be load from a REST API
    this.questions.push({
      id: 1,
      label: 'First Name',
      type: 'input',
      answer: 'Antoine',
      validate: "required|alpha"
    }, {
      id: 2,
      label: 'Last Name',
      type: 'input',
      validate: "required|alpha|min:2"
    }, {
      id: 3,
      label: 'Email',
      type: 'input',
      validate: "required|email"
    }, {
      id: 4,
      label: 'Job',
      type: 'select',
      options: ['...', 'Developer', 'Ops', 'Project Manager'],
      validate: 'in:Developer,Ops,Project Manager',
      answer: 'Developer'
    }, {
      id: 5,
      label: 'Gender',
      type: 'radio',
      options: ['Male', 'Female'],
      answer: 'Male'
    }, {
      id: 6,
      label: 'Address',
      type: 'textarea',
      placeholder: 'Your Pincode and City'
    });
  },
  methods: {
    displayForm: function(event) {
      var $this = this;
      var $validator = this.$validator;
      var data = {};
      this.questions.forEach(function(question) {
        if (question.validate !== undefined) {
          $validator.attach(question.label, question.validate);
          data[question.label] = question.answer;
        }
      });
      var $questions = this.questions;
      $validator.validateAll(data).then(function() {
        var form = [];
        $questions.forEach(function(question) {
          form.push({
            id: question.id,
            label: question.label,
            answer: question.answer
          });
        });
        alert("Valid form: "+JSON.stringify(form));
      }).catch(function(error) {
          $this.$children.forEach(function(child) {
        	child.$children.forEach(function(child) {
          	child.$validator.validateAll();
          });
        });
        alert("Invalid form. Error count:  " + $validator.getErrors().count());
      })
    }
  }
});
<div class="container">
  <div class="page">
    <h2><span>Dynamic Web Form</span></h2>
    <form id="dynform" method="POST" class="panel-body form-horizontal" v-on:submit.prevent="displayForm">
      <div class="row">
        <div class="col-md-12 ">
          <form-question v-for="question in questions" :question="question" :key="question.id"></form-question>
        </div>
      </div>
      <button type="submit" class="btn btn-primary">Submit</button>
    </form>
  </div>
</div>

              
            
          
            
              

External resources loaded into this fiddle: