VeeValidate - check validated input field to enable another input - vue.js

Its my first time using VeeValidate. How can I enable/disable a form field just when another is valid. For example, just enable password field after veevalidate checks the user field as valid.

Wrap both relevant fields in a ValidationObserver and use it's scoped prop errors to tell you when the one field is invalid. Something like this (untested):
<ValidationObserver v-slot="{ errors }">
<ValidationProvider vid="item1" rules="required">
<input v-model="item1" />
</ValidationProvider>
<ValidationProvider vid="item2" rules="required">
<input v-model="item2" :disabled="errors.item1"/>
</ValidationProvider>
</ValidationObserver>

Related

How to Validate vue-ctk-date-time-picker using vuetify in Vuejs with rules?

I am trying to apply required validation for vue-ctk-date-time-picker using :rules.
Its Working for other elements but not working with vue-ctk-date-time-picker
Please correct me.
Here is the script that i am trying
dateTimePickerRules: [(v) => !!v || 'This Field is required'],
<vue-ctk-date-time-picker
id="RangeDatePicker"
v-model="tempInterpreterProjectDate"
classname="form-control"
color="dodgerblue"
:only-date="true"
:no-shortcuts="true"
format="YYYY-MM-DD"
formatted="ddd, MM/DD/YYY"
:range="true"
:rules="dateTimePickerRules"
#input="selectedInterperateDate"
></vue-ctk-date-time-picker>
vue-ctk-date-time-picker is not a Vuetify component. There is no such property as rules. You need to implement a custom validation, e.g. on form submit (check if tempInterpreterProjectDate has a value)
I have managed to validate vue-ctk-date-time-picker as follwing.
<ValidationObserver ref="dateTimeRef">
<ValidationProvider
v-slot="{ errors }"
name="Date/time"
rules="required"
>
<vue-ctk-date-time-picker
id="RangeDatePicker"
v-model="tempInterpreterProjectDate"
classname="form-control"
color="dodgerblue"
:only-date="true"
:no-shortcuts="true"
format="YYYY-MM-DD"
formatted="ddd, MM/DD/YYY"
:error-messages="errors"
:range="true"
#input="selectedInterperateDate"
></vue-ctk-date-time-picker>
<span class="v-messages theme--light error--text">{{
errors[0]
}}</span>
</ValidationProvider>
</ValidationObserver>
I am validating this field something like this
// it will return eithter true or false
const isDateTimeValid = await this.$refs.dateTimeRef.validate()

How to properly test vuetify form validation error with cypress?

I have two text input fields in my vuetify form and I want to test validation errors for each of them separately. but I can't find a way to make sure which error element belongs to which input. I mean I can't find the proper selector.
This is a pseudo form:
<v-text-field
...
:error-messages="emailErrors"
data-cy="email"
></v-text-field>
<v-text-field
...
:error-messages="passwordErrors"
data-cy="password"
></v-text-field>
<v-btn type="submit" >Login</v-btn>
And this is the result produced when form has some validation errors for password field:
<div class="v-input v-input--has-state">
<div class="v-input__control">
<div class="v-input__slot">
<div class="v-text-field__slot">
<input data-cy="password" id="input-29" type="text" />
</div>
</div>
<div class="v-text-field__details">
<div class="...." role="alert">
<div class="...">
<div class="v-messages__message">password is required</div>
</div>
</div>
</div>
</div>
</div>
Notice how data-cy is acting as an attribute for input field only, therefor can not be used to find error element related to password, I can create cypress test to check if there are any validation errors in the form like this:
it('shows password validation error', () => {
cy.visit(loginUrl)
cy.cyElement('email').type('test#email.com')
// do not fill password
cy.get('button').submit()
cy.get('.v-messages__message').should('not.be.empty')
})
but I can't make sure that this validation element is really related to the password! it just checks if there are any validation errors in the form and asserts ok if yes.
One way to do it would be wrapping all vuetify components inside but it is not perfect at all.
Thank you so much in Advance!
It seems like a traversal task. You can use parents() to navigate to the common parent, and then find() the children with the specific class 'v-messages__message'.
cy.get("[data-cy=email]")
.parents(".v-input__control")
.find(".v-messages__message")
.should("contain.text", "email is required")
Here is a handy cheatsheet with all the commands available in traversing the dom: https://example.cypress.io/commands/traversal
While Igor's answer is technically correct, you don't need to know so much about the structure of the app.
Since contains works on the element specified and it's children, you can assert the message exists somewhere on the form.
cy.get('[data-cy="email"]')
.parents('form')
.should('contain', 'password is required')
or if you have data-cy="login-form" on the <v-form>,
cy.get('[data-cy="login-form"]')
.should('contain', 'password is required')

ValidationProvider need to validate after submit Vue 2

I am using ValidationObserver and ValidationProvider for validating the email field.
<ValidationProvider
name="email"
rules="required|max:50|email"
v-slot="{ errors }"
>
<md-field
class="border-round-10 border_box"
:class="{ 'md-invalid': errors.length > 0 }"
>
<label>Email </label>
<md-input
v-model="email"
#blur="greatToSeeYou()"
></md-input>
<span class="md-error">{{ errors[0] }}</span>
</md-field>
</ValidationProvider>
I want to validate the email only after the submit button. I tried so many options but didn't work.
There is 4 modes to configure ValidationProvider: aggressive, lazy, eager and passive.
From your requirement, you would like to validate the form on submission only so you can choose passive mode
<ValidationProvider
name="email"
rules="required|max:50|email"
v-slot="{ errors }"
mode="passive"
>
...
</ValidationProvider>
Here is the codesandbox example I made for your reference:
https://codesandbox.io/s/kind-breeze-rbf27?file=/src/components/HelloWorld.vue:146-293

Validate vue-select with vee-validate

I'm new to VueJS.
I'm trying to validate vue-select using vee-validate.
I've tried to validate it manually but of course its not a good approach.
So, I tried to use vuelidate but couldn't get the desired result.
Now i'm trying to use vee-validate. Validation works fine as desired
but the issue is v-model.
I created a global variable product, to calculate the length of array, and passed it in v-model. So that when Its empty product's value will be zero and i can return desired result from vee-validation.
Here's the .vue html part.
<ValidationObserver>
<form #submit.prevent="add">
<div class="row row-xs mx-0">
<label class="col-sm-4 form-control-label">
<span class="tx-danger">*</span> Add product(s):
</label>
<div class="col-sm-8 mg-t-10 mg-sm-t-0">
<ValidationProvider rules="required" v-slot="{ errors }">
<v-select
name="product"
placeholder="Add product(s)"
:options="availableProducts" <-- here is the options array
:reduce="name => name"
label="name"
#input="setSelected"
v-model="product" <-- this calculates length and pass it to vee **extends**
>
</v-select>
<div v-for="error in errors" :key="error"> {{ error }} </div>
</ValidationProvider>
</div>
<!-- col-8 -->
</div>
</form>
</ValidationObserver>
Here's validation.js file
import { extend } from 'vee-validate';
extend('required', value => {
console.log(value);
return value > 0;
});
I don't want this product value there. I know its not a good approach as well. I can't pass whole array to v-model because then I can't push options in it. I can't pass a single option to v-model as well then I won't get desired result.
All I want to validate v-select when options array is empty. Any suggestions?
Veevalidate doesn't validate directly on select elements. This is my workaround.
You should create a v-field "hidden" input and a visible select v-model element. The veevalidate will take place on the v-field.
Here is an example.
<v-field type="text" class="form-control disabled" name="expirationMonth" v-model="expirationMonth" :rules="isRequired" style="display:none;"></v-field>
<select v-model="expirationMonthUI" class="form-control" #click="synchExpirationMonthUI">
<option value="January">January</option>
<option value="February">February</option>
<option value="March">March</option>
<option value="April">April</option>
<option value="May">May</option>
<option value="June">June</option>
<option value="July">July</option>
<option value="August">August</option>
<option value="September">September</option>
<option value="October">October</option>
<option value="November">November</option>
<option value="December">December</option>
</select>
<error-message name="expirationMonth"></error-message>
Then add this to your methods to synch both together.
synchExpirationMonthUI() {
this.expirationMonth = this.expirationMonthUI;
}
I have found a way of doing this, with the Rendering Complex Fields with Scoped Slots from the Vee-Validate documentation. And using the bindings from Vue Select, it looks something like this:
<Field name="supportType" v-slot="{ field }" v-model="supportType">
<v-select :options="mediaTypes" label="name" :reduce="mediaType => mediaType.id" v-bind="field">
</v-select>
</Field>
As you can see, I am using here the name, v-slot and v-model for the Field from Vee-Validate, as normal. But the v-slot is very important as it carries the information from Vue Select to Vee-Validate, or at least I think so.
On the other hand I use the options, label, reduce and v-bind from Vue Select, these I use to handle the information. So with the :options I select my dataset, with label I tell Vue Select which label to select and show from the dataset, with :reduce I tell Vue Select what will be the value of the select tag and finally use v-bind to bind the value of the select to the Vee-Validate field. So the information used on the :reduce property will be displayed on the v-model="supportType".
I tested it with a button and it worked. And I liked this way so it is not that messy and I can use the validation and other things as usual.
Hope this helps anyone.
PD: I am using Vue 3, and the latest package of both Vee-Validate and Vue Select, as of today.

How to have Or between vee-validate3 rules?

i have an input that its value can be username or email
consider this:
<ValidationProvider name="email" rules="username || email" v-slot="{ errors, valid }">
<v-text-field
v-model="something"
:error-messages="errors"
:success="valid"
label="E-mail or userName"
required
></v-text-field>
</ValidationProvider>
I need Or between rules. if one of them match pass the input.
rules="username or email"
how to achieve this in vee-validate3?
I found there is no or in vee validation
in case you want to or something you have to write custom validator and in the logic of the custom validation you are free to do anything.