Once I submit the form I clear the fields and I want to clear the errors as well, but I'm having a hard time trying to do that.
Form:
<form role="form" class="form-horizontal" @submit.prevent="persistData">
<legend>Supervisor & Deputy Requests</legend>
<div class="form-group">
<label for="requesttype" class="col-sm-2 control-label">Request type</label>
<div class="col-sm-10">
<select v-model="form.requesttype" name="form.requesttype" id="requesttype" class="form-control"
data-vv-rules="required" v-validate.initial="form.requesttype">
<option value=""></option>
<option value="Option 01">Option 01</option>
<option value="Option 02">Option 02</option>
</select>
<span v-show="errors.has('form.requesttype')" class="text-danger">This field is required</span>
</div>
</div>
<div class="form-group">
<label for="userid" class="col-sm-2 control-label">User ID</label>
<div class="col-sm-10">
<input v-model="form.userid" name="form.userid" type="text" class="form-control" id="userid"
data-vv-rules="required"
v-validate.initial="form.userid">
<span v-show="errors.has('form.userid')" class="text-danger">This field is required</span>
</div>
</div>
<div class="form-group">
<label for="requestdescription" class="col-sm-2 control-label">Request description</label>
<div class="col-sm-10">
<textarea v-model="form.requestdescription" name="form.requestdescription" class="form-control"
id="requestdescription" cols="30"
rows="10" data-vv-rules="required"
v-validate.initial="form.requestdescription"></textarea>
<span v-show="errors.has('form.requestdescription')"
class="text-danger">This field is required</span>
</div>
</div>
<button type="submit" class="btn btn-primary pull-right">Submit</button>
</form>
Persist data method:
let self = this
// Validate All returns a promise and provides the validation result.
this.$validator.validateAll().then(success => {
if (!success) {
// handle error
console.log('Error!')
return
}
axios.post('/static/api/SupervisorDeputyRequest/persistdata.php', queryString.stringify(self.form))
.then(res => {
self.form = {
requesttype: '',
userid: '',
requestdescription: ''
}
})
I want to clear the errors in the AJAX callback. This code is in a .vue file and vee-validate is being imported in the main.js file.
I did, but it doesn't work. It seems that "errors" doesn't have a clear() method when I call it. This is what I see if I print "this.errors":

Perhaps I'm missing something?
methods should appear in the __proto__ property.
I'm not sure what could be wrong, but here is a fiddle that seems to be working fine:
Actually what I was missing is the v-validade directive. I was adding v-validate.initial="field" instead =/. I had misunderstood that part. Sorry about that and thanks for your time and great job on this plugin.
Its okay, glad it worked.
@badcom I have this problem. Can you explain how you solved it?
I've showed above what the problem was. If you paste your code here for in fiddle js I can try and help.
@logaretm why when I do this from my code it does not work:
this.$http.post('/api/services', {name: service}).then( ( response ) => {
this.service = "";
this.buttonMessage = 'Guardar';
this.REQUEST_ON_WAY = false;
this.errors.clear();
}

I still see the errors even after the request is over.
But if from the console I do this:

The errorBag does clear successfully.

Very confused right now.
I can't tell the problem from your snippet, I guess something else happens after the request is completed, like you could be resetting the form after the request completes which triggers validation.
If that is the case you can move the clear method call to after the form reset. otherwise can you provide me with a larger sample of your code? maybe just the component code.
@logaretm
This is all the code from my component.
<template>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Nuevo Servicio</h4>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label for="serviceName">Nombre</label>
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-thumb-tack" aria-hidden="true"></i></span>
<input type="text" name="service" v-model="service" v-validate="service" data-vv-rules="required|min:4" data-vv-as="El servicio" placeholder="Escribe aqu铆 el nombre el nombre del servicio" class="form-control" id="service" autocomplete="off">
</div>
<p class="text-danger form-error" v-show="errors.has('service')">{{ errors.first('service') }}</p>
</div>
<div class="form-group">
<button type="button" class="btn btn-default is-warning" data-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-default is-primary" :class="{loading: REQUEST_ON_WAY}" :disabled="REQUEST_ON_WAY || errors.any()" @click="addService(service)">{{buttonMessage}} <i :class="REQUEST_ON_WAY ? 'fa fa-spinner fa-spin' : 'fa fa-plus'" aria-hidden="true"></i></button>
<span v-show="errors.any()" class="text-danger form-error">Check the form for errors <i class="fa fa-exclamation-triangle" aria-hidden="true"></i></span>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
export default{
created(){
},
mounted(){
// Focus the input when modal is loaded.
$('#myModal').on('shown.bs.modal', () => {
$('#service').focus();
});
},
data(){
return {
buttonMessage: 'Guardar',
service: '',
REQUEST_ON_WAY: false,
}
},
methods: {
addService(service){
// Run the validation
this.$validator.validateAll().then( (success) => {
if (! success) {
alert('Hay errores en el formulario');
return;
}
// If there is no error.
let parent = this.$parent
this.REQUEST_ON_WAY = true;
this.buttonMessage = 'Cargando...';
this.$http.post('/api/services', {name: service}).then( ( response ) => {
this.service = "";
this.buttonMessage = 'Guardar';
this.REQUEST_ON_WAY = false;
this.errors.clear();
}, (response) => {
let ERROR_MESSAGE = 'No se ha guardado el servicio';
let ERROR_HEADER = 'Error';
if (response.body.SERVICE_EXISTS == true) {
ERROR_MESSAGE = 'Ya existe un servicio con ese nombre';
ERROR_HEADER = 'Duplicaci贸n';
}
parent.$options.methods.createOverlayAlert(ERROR_HEADER, ERROR_MESSAGE, 'error');
this.buttonMessage = 'Guardar';
this.REQUEST_ON_WAY = false;
});
});
},
}
}
</script>
In the addService method is where I save the service via Ajax.
Probably because the changes to the model value is being done slower that the errors being cleared, you can append another .then in which you can clear the errors.
here is a small example: https://jsfiddle.net/hcac5je0/1/
@logaretm Thanks so much. This seemed to fix my problem. Kinda funny how this was affecting me.
Just stumbled upon this thread when a friend asked me for help. I'd recommend you guys read more about Vue's reactivity system and async update queue in particular.
The gist is that model changes are not flushed immediately when you change a particular model property. Changes are batched and deferred to the next tick for optimal performance. Vue provides nextTick hook that allows you to execute code right after the reconciliation had been performed. It's probably a better idea than using setTimeout directly because it is a publicly documented API which will always yield the best and most reliable results.
EDIT: Polished the text and reinforced the reasoning.
@mareksuscak thanks for your comment, you are correct but I'm not using timeout to clear the errors, its to emulate a server response time. I just chain another then callback and it seems to work fine.
but you are correct, nextTick should be preferred, since it is there to handle such cases.
In my case, i forgot to add the scope of the form i wanted to reset the errors for.
this.errors.clear('my-scope') did the trick.
Just fyi.
I'm still struggling with this problem. I'm using this.$nextTick() to only reset the validator after model changes are flushed, but this is still too fast, since the validation error messages appear below the fields right after they are cleared. Using a timeout of 1000ms instead of $nextTick does do the trick, but is less nice because it is so slow that you see the validator messages appear and disappear again....
~javascript
// Called after a succesfull post request
reset(){
// Clear the form fields
this.accommodation = {...template.fields};
// Reset the validator after the next tick
this.$nextTick()
.then(() => {
this.$validator.reset();
this.errors.clear();
});
}
~
Any idea what I'm doing wrong? I found a mention of this issue on several locations, but none with a conclusive solution (and all were quite dated: $validator.clean has been depecrated in favor of $validator.reset in the mean time).
Hey,
I was having issues with clearing form inputs and resetting the errors much like a few here.
I'd basically set inputs to null on submit and then run this.$validator.reset(), it didn't work.
The thing you have to remember is javascript is naturally asynchronous so, when you fire a function it's running all the code at the same time, or attempting to, and that's my rough understanding.
SO what I did was run an async function :
const clear = async () => {
this.contact.firstName = null
this.contact.lastName = null
this.contact.email = null
this.contact.message = null
}
And then call it that function. After it has completed I call the rest:
clear().then(() => {
this.$validator.reset()
})
And it works for me. Hopefully that helps someone else.
I'm going to try that out as soon as I'm able to. Seems pretty straightforward and logical to me. Maybe they should put an entry about this in the documentation?
Alas, it doesn't work for me and the same problem still persists.
~~~javascript
import template from '../../templates/accommodation';
...
methods:{
save(){
this.$validator.validateAll()
.then(result => {
if(result === false) return;
this.$emit('clicked-save', this.accommodation);
});
},
reset(){
const clear = async () => {
this.accommodation = {...template.fields};
};
clear().then(() => {
console.log('Resetting validator');
this.$validator.reset();
});
}
}
~~~
I store all fields and their default values in separate template files and clone that object again when I reset the form. It might be that this action negates this solution.
Regardless, I solved this problem for now by adding a short timeout before calling $validator.reset(); not very elegant (as you still see the validation errors for a short time), but it does do the trick. You're right at least that this seems to be a concurrency issue.
Got a little more info on this. I have configured vee-validate with this setting:
~javascript
Vue.use(VeeValidate, {
inject: false,
delay: 500
});
~
So, obviously, vee-validate validates the fields 500 ms after they change. This problem might be a race condition between:
I think this could be solved by letting the reset() function also cancel all function that are fired with a timeout or interval?
I had to modify the code provided by @devanflaherty to basically wait for two event loop iterations. I reset the data, waited for nextTick, resolved and waited for another nextTick in the then callback. Code below:
methods:{
clearFormData () {
return new Promise(resolve => {
Object.assign(this.$data, this.$options.data.call(this));
this.$nextTick().then(() => resolve());
});
},
resetForm () {
return new Promise(resolve => {
this.clearFormData().then(() => {
this.$nextTick().then(() => {
this.$validator.reset();
this.errors.clear();
resolve();
});
});
});
}
}
Not the most performant solution, but it seems to be a stable stopgap for the moment.
Also, FYI @dschreij, notice the line where I reset the data in the component. Using Object.assign(this.$data, this.$options.data.call(this)); will reset the components data to its default values. Its a useful shorthand way of doing it.
I used Promise.prototype.then() and worked for me.
I created a method called _clear_ for clear all inputs and other called _createMessage_ for submit:
methods: {
clear () {
this.email = ''
this.message = ''
this.subject = ''
}
createMessage: function (event) {
this.$validator.validateAll().then(function (result) {
if (result) {
...Your Mutation...
new Promise(function (resolve, reject) {
resolve('Reset Form!')
that.clear()
}).then(() => {
that.$validator.reset()
})
}//if
)}//validator
}//createMessage
}//methods
Sorry about the confusing reset behavior guys, Its being already wrapped in a vm.$nextTick call which should in theory reset them correctly but it doesn't work out, I probably will wrap it instead in a setTimeout for 2 ticks instead, since double wrapping the reset in a $nextTick seems to work in my tests due to vue needing two ticks, one to update the fields, another to update the errors.
I should be able to get a quick release today with these changes
Is there a good and easy solution? I struggle with the same problem.
cancel: function () {
this.comment = this.newComment();
this.errors.clear();
}
The text in the form disappears but after that the error that the comment body can't be empty comes up again. :( I've tried to wrap the two lines inside a nexttick() callback but this didn't made it work either.
@burzum errors.clear isn't enough, as it doesn't reset the validator state like flags and does not respect Vue ticks, use validator.reset instead:
@logaretm Your solution works like a charm. Thanks a lot
just do it:
this.errors.items=[]
(you may see THE ERRORS like {{errors}} and understand - what you must CLEAR)
Most helpful comment
Hey,
I was having issues with clearing form inputs and resetting the errors much like a few here.
I'd basically set inputs to null on submit and then run
this.$validator.reset(), it didn't work.The thing you have to remember is javascript is naturally asynchronous so, when you fire a function it's running all the code at the same time, or attempting to, and that's my rough understanding.
SO what I did was run an async function :
And then call it that function. After it has completed I call the rest:
And it works for me. Hopefully that helps someone else.