In some cases some people have reported that they have not entered into the input form fields, investigating this issue, i have happened in Chrome for Android (At least is the browser and have been able to reproduce this error) field is not disabled or readonly, field is focuses and cursor is blinking but no typing is allowed. Two way binding seems to work because vee-validate return the error message related to this field.
After some testing i discover that this problem is related with the event field configuration, after change from event: 'input|blur' to event: '' this issue stops happening.
To reproduce his error you need to build the project and test this build with Chrome for Android. If you change from events: 'input|blur' to events: '' it stops happening.
import Vue from 'vue'
import VeeValidate, {Validator} from 'vee-validate'
const dict = {
es: {...},
en: {...}
}
Validator.localize('es', dict)
const config = {
events: 'input|blur'
}
Vue.use(VeeValidate, config)
<input type="text" class="form__input" name="name" id="name" v-model="element.name" v-validate="'required|min:3|max:250'">
<span v-show="errors.has('name')" class="help is-danger form__alert">{{ errors.first('name') }}</span>
Try to change v-model element.name" to just name, it should work. I noticed that when v-model is presented and has an object name the validation on Android phones goes crazy and not allows you to type.
But if you get the content dynamically as an object from an API and then update same information it is simpler just to use it as an object.
I agree with that and I was using object name as well until I noticed this problem. As a quick alternative, I came up with this solution as I don't have time. Hopefully, it will be fixed later on.
Okay this looks similar to #1251
Which was closed due to it being hard to reliably produce, for reference it happens when your data looks like this:
data: () => ({
element: {}
});
See that it lacks the name attribute when it does have it initially it works just fine. I will try to test that again and see if I can come up with a solution.
Hi - I think I'm experiencing the same issue, although using same versions as above of vue / vee validate integrated with ASP.NET - so appreciate this may not be the ''standard' way! I'm just importing the vue and vee validate CDN scripts into a 'standard' html page / form...but the difference is, I'm using an api call-back (in the vue 'created' hook) to populate my vue data model from c# classes.
This has been working really well, meaning I can avoid having to re-create complex server models in JavaScript. Everything works perfectly when testing on a Windows pc using various browsers. However, when testing on android, any form inputs with validation do not allow any input, despite allowing selection of characters on keyboard / drop down select items - but then just empty boxes. Validation still highlights the field is 'required' (which is expected if there's still nothing in the input box) Removing validation or adding vee validate config of "events: ''" fixes the input issue....but obviously removes key functionality.
data: {
model: { }
},
methods: {
createModel: function () {
var self = this;
var uri = '../api/x'
axios.get(uri)
.then(function (response) {
self.model = response.data;
})
.catch(function (error) {
});
},
},
created: function () {
this.createModel();
},
Also a massive thanks to everyone involved with these projects - having come from a .NET background it certainly takes some adjusting to the JavaScript eco system...but I'm absolutely loving learning vue and libraries such as vee validate that complement it so well!!!
@LeeW32 When you receive your data from the ajax call, you should use this.$set to set your model, otherwise, you lose reactivity
axios.get(uri).then(function (response) {
// self.model = response.data;
this.$set(self, 'model', response.data);
})
@nicokoenig Thanks for your suggestion - I clearly need to read up some more on that, however your original line above fails with the error: "this.$set is not a function". Changing the line to:
self.$set(self, 'model', response.data);
...gets everything working as before - from a pure Vue aspect, there's no difference - everything on the page is as reactive as it always was (at least just from basic tests in chrome / vue dev tool - I'm sure under the hood things are different as you suggest). When I bring in Vee Validation, everything works as expected on browsers on a pc - but the moment I use an android device, input (ie
@LeeW32 Sure, that need to be self, since you have a closure there... that's my fault, sorry 馃樅
In @LeeW32 case the issue occurs because the additional properties on the model are not watchable at the time of binding, which causes the same observation I noted earlier about having to define all props beforehand.
Like @nicokoenig suggested, $set would work because it sets the attributes and allows them to be reactive, or watchable. I believe it is a recommended practice to define your data properly beforehand and using Object.assign to define new props in objects, I think Vue used to complain about this in a warning saying "consider per-initializing the prop" or something similar. When your data is not defined in a nested path.
Now, I will try to re-explain what happens here to discuss potential solutions:
VeeValidate identifies the v-model on the element, and tries to defer the watching to Vue using $watch API method. But the model maybe unwatchable, for example in v-for loop like:
<input v-for="i in inputs" v-model="i.value" v-validate="'required'">
The model exists within the v-for context, but not outside it. Meaning you cannot use $watch to watch the model. So VeeValidate has a couple of fallbacks here. First it checks if the input is a component, if so It will instead try to watch the model from that component, it should be much easier since it would just watch the value prop in that input component. But for native HTML inputs this is not possible.
The last fallback is that it adds event listeners on the element and uses whatever events are configured. Now there are some caveats here. v-model doesn't work the same on mobile devices and desktops because of the composition events (not all browsers tho). So when you enter a value the input event emits as per the HTML5 Spec so it gets validated and the error would be displayed, but there is already a DOM update in progress which tries to update the field value on the UI. What happens is when the error is added to the error bag, the UI update will get blocked. In other words, the errorbag will cause a re-render before the DOM is updated i.e: validates before the value is committed to the input.
There a couple of workarounds, define your props beforehand. Use change event for mobile devices using a useragent detection script, or use $set like @nicokoenig mentioned.
Fixing this issue is hard, since I will not be adding a user-agent detection script to this library, I hope I will not have to. I have been thinking about trying to make the errors added/removed on the next Vue tick or the next DOM update if there is a pending one, need to dig deeper into vue for this.
Getting there...thanks @logaretm especially for your detailed response - again, this is a fantastic library. I've managed to get it working - using $set and reading through the vue reactive documentation suggested by @nicokoenig things are starting to make sense.
For anyone reading this and having similar issues, the final thing I needed to solve was the same issue for any array items in the model (ie when using v-for). I was initiating everything in my c# classes as 'null' - which again, works fine on pc but not android. Once I changed any strings to "" or empty.string, everything now seems to work on most devices - ipad, android & pc.
@LeeW32 I have a small background in C#, I believe there is not an undefined type in C# so the props initialized to null would be omitted from the response, like Node.js and initializing props to undefined.
Most helpful comment
In @LeeW32 case the issue occurs because the additional properties on the model are not watchable at the time of binding, which causes the same observation I noted earlier about having to define all props beforehand.
Like @nicokoenig suggested,
$setwould work because it sets the attributes and allows them to be reactive, or watchable. I believe it is a recommended practice to define your data properly beforehand and usingObject.assignto define new props in objects, I think Vue used to complain about this in a warning saying "consider per-initializing the prop" or something similar. When your data is not defined in a nested path.Now, I will try to re-explain what happens here to discuss potential solutions:
VeeValidate identifies the
v-modelon the element, and tries to defer the watching to Vue using$watchAPI method. But the model maybe unwatchable, for example inv-forloop like:The model exists within the
v-forcontext, but not outside it. Meaning you cannot use$watchto watch the model. So VeeValidate has a couple of fallbacks here. First it checks if the input is a component, if so It will instead try to watch the model from that component, it should be much easier since it would just watch thevalueprop in that input component. But for native HTML inputs this is not possible.The last fallback is that it adds event listeners on the element and uses whatever events are configured. Now there are some caveats here.
v-modeldoesn't work the same on mobile devices and desktops because of the composition events (not all browsers tho). So when you enter a value theinputevent emits as per theHTML5 Specso it gets validated and the error would be displayed, but there is already a DOM update in progress which tries to update the field value on the UI. What happens is when the error is added to the error bag, the UI update will get blocked. In other words, the errorbag will cause a re-render before the DOM is updated i.e: validates before the value is committed to the input.There a couple of workarounds, define your props beforehand. Use
changeevent for mobile devices using a useragent detection script, or use$setlike @nicokoenig mentioned.Fixing this issue is hard, since I will not be adding a user-agent detection script to this library, I hope I will not have to. I have been thinking about trying to make the errors added/removed on the next Vue tick or the next DOM update if there is a pending one, need to dig deeper into vue for this.