The new validation components make sense to me and I'm currently converting my code to use them.
However I encountered some problems.
1) How to fill server side validation errors? This is what I've done before:
forEach(errors, (errs, key) => {
const field = this.$validator.fields.find({ name: key, scope: this.$options.scope })
if (field) {
this.$validator.errors.add({
id: field.id,
field: key,
msg: errs[0],
scope: this.$options.scope
})
field.setFlags({
invalid: true,
valid: false,
validated: true
})
}
})
2) I tried to use a ValidationObserver together with a ValidationProvider but got an error. Is that not possible and how should it be done?
<ValidationObserver ref="userData">
<template slot-scope="{ invalid }">
<ValidationProvider rules="required|alpha_num|min:3|max:16">
<template slot-scope="{ errors }">
<v-text-field
type="text"
name="username"
prepend-icon="person"
label="Nutzername"
color="primary"
v-model="username"
data-vv-as="Nutzername"
:error-messages="errors"
></v-text-field>
</template>
</ValidationProvider>
<ValidationProvider rules="required|email">
<template slot-scope="{ errors }">
<v-text-field
type="email"
name="email"
prepend-icon="email"
label="E-Mail Adresse"
color="primary"
v-model="email"
data-vv-as="E-Mail Adresse"
:error-messages="errors"
></v-text-field>
</template>
</ValidationProvider>
<ValidationProvider rules="required|min:8|max:72">
<template slot-scope="{ errors }">
<v-text-field
:type="showPassword ? 'text' : 'password'"
vid="password"
name="password"
prepend-icon="lock"
:append-icon="showPassword ? 'visibility_off' : 'visibility'"
label="Passwort"
color="primary"
v-model="password"
data-vv-as="Passwort"
:error-messages="errors"
@click:append="showPassword = !showPassword"
></v-text-field>
</template>
</ValidationProvider>
<ValidationProvider rules="required|confirmed:password">
<template slot-scope="{ errors }">
<v-text-field
:type="showPasswordConfirmation ? 'text' : 'password'"
name="password_confirmation"
prepend-icon="lock"
:append-icon="showPasswordConfirmation ? 'visibility_off' : 'visibility'"
label="Passwort wiederholen"
class="mb-3"
color="primary"
v-model="password_confirmation"
data-vv-as="Passwort wiederholen"
:error-messages="errors"
@click:append="showPasswordConfirmation = !showPasswordConfirmation"
></v-text-field>
</template>
</ValidationProvider>
<v-btn color="primary" @click="preRegister" :disabled="invalid">
Weiter
</v-btn>
</template>
</ValidationObserver>
3) Since vue 2.5.x it is possible to use the scoped-slot feature on other things than template.
Would it be possible to do <ValidationProvider slot-scope="{ errors }"> to safe some lines?
How to fill server side validation errors?
Currently there is no API to do that, but there is nothing stopping you from:
<ValidationProvider rules="required|confirmed:password" ref="password">
<!-- ..... -->
</ValidationProvider>
<script>
this.$refs.password.errors = errorsArrayFromServer;
</script>
I will try to come up with a more suitable API for it.
I tried to use a ValidationObserver together with a ValidationProvider but got an error.
They are meant to be used together, an observer isn't useful without having some child providers. This example uses them both. Would be more useful if you describe what type of errors are you getting.
Since vue 2.5.x it is possible to use the scoped-slot feature on other things than template.
Would it be possible to doto safe some lines?
You can place slot-scope on any root element inside the validation provider component, but not on itself. Quoting this from the docs:
"In 2.5.0+, slot-scope is no longer limited to the element, but can instead be used on any element or component __in the slot__."
Currently only the template is allowed, a fix was implemented for other tags as well, which should be released soon. So you can do this (if you are using vuetify):
<ValidationProvider rules="required">
<v-text-field slot-scope="{ errors }" v-model="value" :error-messages="errors"></v-text-field>
</ValidationProvider>
You can customize the provider tag rendered using the tag prop, for example if you are doing bootstrap things:
ValidationProvider tag="div" class="form-group"
Which should help you with reducing the markup a bit. If you are really looking to reduce the markup considerably, I recommend reading the docs refactoring section
Thank you for your answers, really made some things clear.
For the error mentioned in 2), this is what I found out:
This is the error:
[Node] [Vue warn]: Error in render: "ReferenceError: Event is not defined"
[Node]
[Node] found in
[Node]
[Node] ---> <ValidationProvider>
[Node] <ValidationObserver>
[Node] <VStepperContent>
[Node] <VStepper>
[Node] <VCard>
[Node] <Pages/register.vue> at pages/register.vue
[Node] <Nuxt>
[Node] <VContent>
[Node] <VApp>
[Node] <Default> at layouts/default.vue
[Node] <Root>
[Node] [18:56:55] ReferenceError: Event is not defined
[Node] at isEvent (/Users/pascal/code/web/node_modules/vee-validate/dist/vee-validate.js:5712:24)
[Node] at VueComponent.syncValue (/Users/pascal/code/web/node_modules/vee-validate/dist/vee-validate.js:7951:21)
[Node] at Proxy.onRenderUpdate (/Users/pascal/code/web/node_modules/vee-validate/dist/vee-validate.js:7767:12)
[Node] at Proxy.addListeners (/Users/pascal/code/web/node_modules/vee-validate/dist/vee-validate.js:7810:20)
[Node] at /Users/pascal/code/web/node_modules/vee-validate/dist/vee-validate.js:8065:22
[Node] at Array.forEach (<anonymous>)
[Node] at Proxy.render (/Users/pascal/code/web/node_modules/vee-validate/dist/vee-validate.js:8064:42)
[Node] at VueComponent.Vue._render (/Users/pascal/code/web/node_modules/vue/dist/vue.runtime.common.js:4542:22)
[Node] at renderComponentInner (/Users/pascal/code/web/node_modules/vue-server-renderer/build.js:7532:25)
[Node] at renderComponent (/Users/pascal/code/web/node_modules/vue-server-renderer/build.js:7502:5)
[Node] at RenderContext.renderNode (/Users/pascal/code/web/node_modules/vue-server-renderer/build.js:7418:5)
[Node] at RenderContext.next (/Users/pascal/code/web/node_modules/vue-server-renderer/build.js:2436:14)
[Node] at cachedWrite (/Users/pascal/code/web/node_modules/vue-server-renderer/build.js:2295:9)
[Node] at renderElement (/Users/pascal/code/web/node_modules/vue-server-renderer/build.js:7656:5)
[Node] at renderNode (/Users/pascal/code/web/node_modules/vue-server-renderer/build.js:7420:5)
[Node] at renderComponentInner (/Users/pascal/code/web/node_modules/vue-server-renderer/build.js:7538:3)
This is actually a bug :man_facepalming: I will try to release a fix tomorrow
Okay, will try it out again when the release is out.
Update: This issue was resolved a couple of days ago, but I would like to take more time to smooth things around the edges with SSR in general.
Okay, any ETA on when a fix will be released?
Also for inserting server side validation errors, I tried the solution you gave but it was not working.
Would be great if you could give another example and explain the structure of errorsArrayFromServer.
Another thing that changed with the new components is localization. I was doing this to give custom error messages for some fields:
VeeValidate.Validator.localize({
de: Object.assign(deLocale, {
custom: {
password: {
confirmed: 'Die eingegebenen Passwörter stimmen nicht überein.'
}
}
})
})
However this does not seem to work anymore. I tried setting vid="password" on the validation provider but that did not help either. How should that be done?
I'm still waiting for #1698 to be confirmed to fix the issues mentioned in there, otherwise I can release it today/tomorrow. You can clone the repo and use the updated version now if you would like.
Also for inserting server-side validation errors, I tried the solution you gave but it was not working.
Sorry I didn't realize I gave you the wrong prop name, the messages prop is the one which holds the error messages. Here is an example:
<ValidationProvider rules="required" ref="name">
<div slot-scope="{ errors }">
<input v-model="value" type="text">
<span id="error">{{ errors[0] }}</span>
</div>
</ValidationProvider>
Then add your errors like this:
// place a message as the first item.
this.$refs.pro.messages.unshift('MY MESSAGE');
// ADD multiple messages as the last items
const messages = ['first', 'second', 'third'];
this.$refs.pro.messages.push(...messages);
Another thing that changed with the new components is localization ...
vid is only used for cross-field validation. Use the name prop, I will add a note in the docs.
Nice, using the name property on the ValidationProvider works fine for localization.
Pushing to the messages array also works fine. I like that the process is much simpler than before (just pushing to the error now detects that the field is invalid without the need to find the field first and setting field flags).
Yep, everything is neatly packed with those components! some stuff remains to be ironed out.
@logaretm, how about use case when we have multiple ValidationProviders wrapped inside ValidationObserver, like this:
<ValidationObserver ref="observer">
<form slot-scope="{ invalid }">
<ValidationProvider rules="required">
<base-range-input v-model="field1" name="field1" label="Field1" min="0" max="10"
slot-scope="{ errors }">
<span class="error-message">{{ errors[0] }}</span>
</base-range-input>
</ValidationProvider>
<ValidationProvider rules="required">
<base-range-input v-model="field2" name="field2" label="Field2" min="0" max="10"
slot-scope="{ errors }">
<span class="error-message">{{ errors[0] }}</span>
</base-range-input>
</ValidationProvider>
<div class="text-center">
<button class="btn btn-default"
:class="{'disabled': invalid}"
@click.prevent="submitForm">Submit
</button>
</div>
</form>
</ValidationObserver>
Is there a way to programmatically add an error to a specific child in this case other than treat each one separately using specific ref attribute names and match them to api response name fields?
There also might be a situation with complex forms when having lots of nested components is inevitable and in this case using refs for each nested validation provider to place backend errors cannot be a solution.
I tried attaching custom error to observer's ErrorBag, but it seems to have no effect
Most helpful comment
@logaretm, how about use case when we have multiple ValidationProviders wrapped inside ValidationObserver, like this:
Is there a way to programmatically add an error to a specific child in this case other than treat each one separately using specific ref attribute names and match them to api response name fields?
There also might be a situation with complex forms when having lots of nested components is inevitable and in this case using refs for each nested validation provider to place backend errors cannot be a solution.
I tried attaching custom error to observer's ErrorBag, but it seems to have no effect