1
votes

Vue.js v2.6.11 / vee-validate v3.2.2

I have a button that will push new element to form.demand (data in vue app) on click event. And if form.demand update, html in v-for should be updated. After I wrap it in vee-validate component , it not works. form.demand will update, but v-for won't. I try to put same html in test-component, when form.demand update, v-for update too. I can't figure out why...

following is my code:

HTML

<div id="content">
<test-component>
  <div v-for="demand in form.demand">{{demand}}</div>
</test-component>

<validation-provider rule="" v-slot="v">
  <div @click="addDemand">new</div>

  <div v-for="(demand,index) in form.demand">
      <div>{{demand.name}}</div>
      <div>{{demand.count}}</div>
      <input type="text" :name="'demand['+index+'][name]'" v-model="form.demand[index].name" hidden="hidden" />
      <input type="text" :name="'demand['+index+'][count]'" v-model="form.demand[index].count" hidden="hidden" />
  </div>
</validation-provider>
</div>

javascript

Vue.component('validation-provider', VeeValidate.ValidationProvider);
Vue.component('validation-observer', VeeValidate.ValidationObserver);

Vue.component('test-component',{
    template: `
        <div>
            <slot></slot>
        </div>
    `
})

var app = new Vue({
    el: "#content",
    data: {
        form: {
            demand: [],
        },
    },
    methods: {
        addDemand(){
            this.form.demand.push({
                name : "demand name",
                count: 1
            })
        }
})

------------Try to use computed & Add :key---------------- It's still not work. I get same result after this change.

HTML

<validation-provider rule="" v-slot="v">
      <div @click="addDemand">new</div>

      <div v-for="(demand,index) in computed_demand" :key="index">
           <!--.........omitted.........-->
</validation-provider>

Javascript

var app = new Vue({
        el: "#content",
        // .......omitted
        computed:{
            computed_demand() {
                return this.form.demand;
            }
        },
    })

I think I found the problem : import Vue from two different source. In HTML, I import Vue from cdn. And import vee-validate like following:

vee-validate.esm.js

import Vue from './vue.esm.browser.min.js';
/*omitted*/

validator.js

 import * as VeeValidate from './vee-validate.esm.js';
    export { veeValidate };

main.js

// I didn't import Vue from vue in this file
import { veeValidate as VeeValidate } from './validator.js';

Vue.component('validation-provider', VeeValidate.ValidationProvider);

HTML

<head>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <!-- at end of body -->
    <script src="/static/javascripts/main.js" type="module"></script>
</body>

After I fix this( import vee-validate from cdn, or import Vue by ES6 module). It works, although it still have infinite loop issue with vee-validate.

Sorry for I didn't notice that import vue from two different source.

1
This is most likely a reactivity issue. Use a getter for fetching the form object if you are using vuex. Else make a computed property instead of using method addDemand - Utsav Patel
Thanks. I am not using vuex. I modified my code, use computed value, but it still not work. - crazydos

1 Answers

0
votes

Please provide a key in you v-for. see code below

<div v-for="(demand,index) in form.demand" :key="index">
      <div>{{demand.name}}</div>
      <div>{{demand.count}}</div>
      <input type="text" :name="'demand['+index+'][name]'" v-model="form.demand[index].name" hidden="hidden" />
      <input type="text" :name="'demand['+index+'][count]'" v-model="form.demand[index].count" hidden="hidden" />
  </div>

Or, make a computed property that will hold your form.demands array, like this one

computed: {
   form_demands: function() {
     return this.form.demand
  }
}

then call this computed property in your v-for

<div v-for="(demand,index) in form_demands" :key="index">
      <div>{{demand.name}}</div>
      <div>{{demand.count}}</div>
      <input type="text" :name="'demand['+index+'][name]'" v-model="form.demand[index].name" hidden="hidden" />
      <input type="text" :name="'demand['+index+'][count]'" v-model="form.demand[index].count" hidden="hidden" />
</div>

Or, use the vue forceUpdate method

import Vue from 'vue';
Vue.forceUpdate();

Then in your component, just call the method after you add demand

this.$forceUpdate();

It is recommended to provide a key with v-for whenever possible, unless the iterated DOM content is simple, or you are intentionally relying on the default behavior for performance gains.