Faris Dewantoro
Faris Dewantoro

Reputation: 1775

Property or method "$v" is not defined using Vuelidate

Error:

[Vue warn]: Property or method "$v" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

found in

---> at resources\assets\js\components\products\Product_create.vue

I'm using Vue.js and Vuelidate as validator, I've copied and pasted this code from here https://jsfiddle.net/Frizi/b5v4faqf/ but it still doesn't work :

Vue Component :

    <template >
      <input v-model="$v.text.$model" :class="status($v.text)">
      <!-- <pre>{{ $v }}</pre> -->
    </template>
    
    <script>
    import { required, minLength, between } from 'vuelidate/lib/validators'
      export default {
         data() {
           return {
        text: ''
            }
           },
           validations: {
            text: {
            required,
            minLength: minLength(5)
          }
        },
        methods: {
            status(validation) {
            return {
                error: validation.$error,
              dirty: validation.$dirty
            }
          }
        }
      }
    </script>

App.js

    require('./bootstrap');
    
    window.Vue = require('vue');
    window.VueRouter = require('vue-router').default;
    window.VueAxios = require('vue-axios').default;
    window.Axios = require('axios').default;
    window.VueFormWizard = require('vue-form-wizard');
    window.Vuelidate = require('vuelidate').default;
    import 'vue-form-wizard/dist/vue-form-wizard.min.css';

    Vue.use(VueRouter,VueAxios,axios,VueFormWizard,Vuelidate);

    const ProductOptionCreate = Vue.component('po-create',require('./components/products/ProductOption_create.vue'));
    const ProgressModal = Vue.component('vue-modal',require('./components/ProgressModal.vue'));
    const ProductIndex = Vue.component('product-list',require('./components/products/Product_index.vue'));
    const productshow = Vue.component('productshow',require('./components/products/ProductOption_show.vue'));
    const ProductCreate = Vue.component('product-create',require('./components/products/Product_create.vue'));
    

    const app = new Vue({
      el:'#app',
    
    });

What's wrong with this code?

Upvotes: 4

Views: 21121

Answers (5)

Viraj Singh
Viraj Singh

Reputation: 2358

The validations should be defined in a component in order to initialize this.$v

I had a typo and didn't realized I was declaring validations inside methods.

methods: {

   validations: {
      isUScitizen: { required },
   },
}

And I was trying to access this.$v which was undefined because the component didn't had validations defined.

Upvotes: 1

MeddlingMonk
MeddlingMonk

Reputation: 41

I think the problem was that the validation was declared within the data property of the component and not as a direct property of the component.

So

export default {
     validations: {
        text: {
        required,
        minLength: minLength(5)
      },
     data() {
       return {
           text: ''
        }
       },
       
    },
    ........

instead of

export default {
     data() {
       return {
          text: ''
        }
       },
       validations: {
        text: {
        required,
        minLength: minLength(5)
      }

Upvotes: 4

tao
tao

Reputation: 90277

The reason $v is not available on your instance is because you haven't instantiated the Vuelidate plugin. And that's because you tried to streamline the call to Vue.use().
Your current Vue.use() call only instantiates the first plugin (VueRouter) and passes VueAxios plugin object as VueRouter's config object. All subsequent arguments are ignored.

To streamline your calls to Vue.use(), you can't simply add more arguments to it.

Instead of this erroneous syntax (which breaks instantiation of all but first plugin):

Vue.use(VueRouter, VueAxios, axios, VueFormWizard, Vuelidate);

... you could use:

[[VueRouter], [VueAxios, axios], [VueFormWizard], [Vuelidate]]
  .forEach(args => Vue.use(...args));

With Typescript: unfortunately, TS parser wrongly includes 0 arguments as a possible outcome of the spread operator in the above case, so you'd need to suppress it using:

[
  [VueRouter],
  [VueAxios, axios],
  [VueFormWizard],
  [Vuelidate]
  /* @ts-ignore: TS2557, TS wrong about array above having empty members */
].forEach(args => Vue.use(...args));

... at least for now ("typescript": "^3.9.7").

The above syntax is the exact equivalent of:

Vue.use(VueRouter);
Vue.use(VueAxios, axios);
Vue.use(VueFormWizard);
Vue.use(Vuelidate); // <= this is what you were missing, basically
                    // but your syntax also broke VueAxios and VueFormWizard install

On a personal note: although a tad more repetitive, I actually find the Vue.use() syntax cleaner in this case (more readable).

Upvotes: 1

You must specify this.$v and there will be no error

Upvotes: -9

Rodrigo Mata
Rodrigo Mata

Reputation: 1859

The problem is that $v is not defined at a component level, and it is because of the order of your components, you need to reorder them like so:

// ... other stuff
import 'vue-form-wizard/dist/vue-form-wizard.min.css';

Vue.use(Vuelidate);

const ProductOptionCreate = // ... rest of your components

Upvotes: 6

Related Questions