I have a legacy Vue2
code for login page. A part of it that is checking for username input field:
...
<validation-observer ref="ref-id" v-slot="{ invalid }">
<v-form>
<v-card-text>
<validation-provider
v-slot="{ errors }"
rules="rulename"
name="username"
>
<v-text-field
v-model="input.username"
label="username"
prepend-icon="mdi-account-circle"
:error-messages="errors"
></v-text-field>
</validation-provider>
...
</v-card-text>
</v-form>
</validation-observer>
...
Now I'm trying to create same code using new versions Vuetify
and vee-validate
(3
and 4
)
I'm able to create v-text-field
with new version of Vuetify
:
<vee-validation-form as="v-form">
<v-card-text>
<!-- <vee-validation-field as="v-text-field" -->
<v-text-field
v-model="input.username"
label="username"
prepend-icon="mdi-account-circle"
:error-messages="errors"
></v-text-field>
<!-- ></vee-validation-field> -->
</v-card-text>
</vee-validation-form>
Where
And this code is at least displaying username
input element.
But when I'm trying to use <vee-validation-field as="v-text-field"
instead of <v-text-field
it shows me error:
ERROR
Cannot read properties of undefined (reading 'split')
TypeError: Cannot read properties of undefined (reading 'split')
at normalizeFormPath (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:100:26)
at ReactiveEffect.eval [as fn] (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1603:70)
at ReactiveEffect.run (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:217:19)
at get value [as value] (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:1178:33)
at unref (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:1057:29)
at _useFieldValue (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1141:70)
at useFieldState (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1044:54)
at _useField (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1618:72)
at useField (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1597:12)
at setup (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:2038:164)
The question is: how to use v-text-field
component with vee-validate
? As I understand correctly here is no ValidationObserver
and ValidationPbserver
components in new vee-validate v4
.
The Field component expects a name
attribute, the error is thrown when it tries to call split()
on the value. Just set a name and the error is gone:
<Field as="v-text-field"
name="username"
...
></Field>
However, label
is a prop of the Field
component, but it only passes attrs (i.e. non-props) to the custom input component (see code), so you cannot pass a label to the v-text-field. Also, you would have to get the error messages through the form.
Looks like using :as
is more trouble than solution at the moment. Probably better to stick with the slot:
<vee-validation-field
v-slot="{ field, errors }"
name="username"
rules="required|needsL"
v-model="username"
>
<v-text-field
v-model="field.value"
v-bind="field"
label="username"
prepend-icon="mdi-account-circle"
:error-messages="errors"
/>
</vee-validation-field>
(the somewhat duplicated v-bind
and v-model
on the VTextField is necessary for them moment due to an issue in vee-validate)
const { createApp, ref } = Vue;
const { createVuetify } = Vuetify
const vuetify = createVuetify()
VeeValidate.defineRule('required', VeeValidateRules.required)
VeeValidate.defineRule('needsL', v => v.toLowerCase().includes('L') || 'Input something with an `l`')
const app = {
components: {
'vee-validation-form': VeeValidate.Form,
'vee-validation-field': VeeValidate.Field,
},
setup(){
return {
username1: ref('user 1'),
username2: ref('user 2'),
}
}
}
createApp(app).use(vuetify).mount('#app')
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.css" />
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
<div id="app">
<v-app>
<v-main>
<vee-validation-form as="v-form" v-slot="{errors}">
<v-card-text>
Field from :as
<vee-validation-field as="v-text-field"
name="username1"
v-model="username1"
prepend-icon="mdi-account-circle"
:error-messages="errors.username1"
rules="required|needsL"
></vee-validation-field>
Field in slot
<vee-validation-field
v-slot="{ field, errors }"
v-model="username2"
name="username2"
rules="required|needsL"
>
<v-text-field
v-model="field.value"
v-bind="field"
label="username"
prepend-icon="mdi-account-circle"
:error-messages="errors"
/>
</vee-validation-field>
</v-card-text>
</vee-validation-form>
</v-main>
</v-app>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vee-validate/4.10.8/vee-validate.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@vee-validate/rules@4.11.0/dist/vee-validate-rules.min.js"></script>