The issue I’m having is due to the input
event that’s being run when I first set a value to the v-model
, this data is being loaded in via an API; I understand why the form is being set to dirty (as this it is being changed) but this causes problems in another component I have which checks if the $v.$anyDirty
flag is sets to true and if it is, creates a pop up to say “are you sure you want to navigate away” but calling $v.reset()
after the data is loaded doesn’t work.
Vue.use(vuelidate.default); const { required } = window.validators; new Vue({ el: "#app", data: { todos: [], todo: "" }, async created() { var data = await axios.get("https://jsonplaceholder.typicode.com/todos"); this.todos = data.data.map(d => d.id); this.todo = this.todos[0]; this.$v.$reset() }, validations() { return { todo: { required } }; } });
<link href="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.css" rel="stylesheet"/> <link href="https://unpkg.com/bootstrap@4.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <script src="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.min.js"></script> <script src="https://unpkg.com/vuelidate@0.7.4/dist/validators.min.js"></script> <script src="https://unpkg.com/vuelidate@0.7.4/dist/vuelidate.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script> <div id='app'> <div class="row"> <div class="col-md-4"> <b-form-select v-model="$v.todo.$model" :options="todos"></b-form-select> </div> <div class="col-md-8"> <code> $anyDirty: {{$v.$anyDirty}} </code> </div> </div> </div>
Advertisement
Answer
The problem is that $v.reset()
is being run before vue renders so the input events happen after, so the stack trace would look like this
load > set values > reset validation > render > input event
You need to put the reset inside Vue.nextTick
and then it’ll work as it’ll change the execution to be
load > set values > render > input event > reset validation
Vue.use(vuelidate.default); const { required } = window.validators; new Vue({ el: "#app", data: { todos: [], todo: "" }, async created() { var data = await axios.get("https://jsonplaceholder.typicode.com/todos"); this.todos = data.data.map(d => d.id); this.todo = this.todos[0]; Vue.nextTick(() => { this.$v.$reset() }) }, validations() { return { todo: { required } }; } });
<link href="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.css" rel="stylesheet" /> <link href="https://unpkg.com/bootstrap@4.1.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <script src="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.min.js"></script> <script src="https://unpkg.com/vuelidate@0.7.4/dist/validators.min.js"></script> <script src="https://unpkg.com/vuelidate@0.7.4/dist/vuelidate.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script> <div id='app'> <div class="row"> <div class="col-md-4"> <b-form-select v-model="$v.todo.$model" :options="todos"></b-form-select> </div> <div class="col-md-8"> <code> $anyDirty: {{$v.$anyDirty}} </code> </div> </div> </div>
As a note, you can also call Vue.nextTick
with this.$nextTick