Infinite targets of custom rule is not working - vue.js

js
VeeValidate.Validator.extend('requireWithoutAll', {
validate: (value, [ ...target ]) => {
return value && _.compact(target).length;
},
getMessage: (field, [...target]) => 'The ${field} is required when none of ${target} are present.'
}, {
hasTarget: true
});
vue
<ValidationProvider name="name1" vid="ref1">
<el-form-item slot-scope="{ errors }" :error="errors[0]" label="Lorum Ipsum 1">
<el-checkbox v-model="is_model_1">Yes</el-checkbox>
</el-form-item>
</ValidationProvider>
<ValidationProvider name="name2" vid="ref2">
<el-form-item slot-scope="{ errors }" :error="errors[0]" label="Lorum Ipsum 2">
<el-checkbox v-model="is_model_2">Yes</el-checkbox>
</el-form-item>
</ValidationProvider>
<ValidationProvider :rules="'requireWithoutAll:ref1,ref2'" name="name3" vid="ref3">
<el-form-item slot-scope="{ errors }" :error="errors[0]" label="Lorum Ipsum 3">
<el-checkbox v-model="is_model_3">Yes</el-checkbox>
</el-form-item>
</ValidationProvider>
Expected Result
When ref1 & ref2 is not selecting, there is error generated on ref3.
Actual Result
Error doesn't generate.

The format for specifying the targets is rules="requireWithoutAll:#ref1,#ref2" not rules="requireWithoutAll:ref1,ref2".
See a working example here: https://codesandbox.io/s/codesandbox-forked-u0s3g?file=/src/Demo.vue
Relevant code:
<ValidationProvider
rules="requireWithoutAll:#ref1,#ref2"
vid="ref3"
v-slot="{ errors }"
tag="div"
>
<!-- your checkbox UI here -->
</ValidationProvider>

Related

Vue 2 - Vee validity manually control valid fields do not working

I use vee-validity (v ^3.4.14) and i have issue:
MyCompontent.vue
<ValidationObserver v-slot="{ handleSubmit }">
<form #submit.prevent="handleSubmit(onSubmit)" >
<ValidationProvider
name="TxF_Loc_Ch1"
:rules="`required|numeric|between: ${$store.state.cnf.rad.txf.minE[0] / 1000}, ${$store.state.cnf.rad.txf.maxE[0] / 1000}`"
v-slot="{ errors, pristine }"
>
<v-text-field
ref="txfLocCh1"
type="number"
v-model="values.upTxfLocCh1"
></v-text-field>
<span
v-if="errors.length > 0"
class="block-error block-error__main"
>{{ errors[0] }}</span>
</ValidationProvider>
<ValidationProvider
name="TxF_Loc_Ch2"
:rules="`required|numeric|between: ${$store.state.cnf.rad.txf.minE[1] / 1000}, ${$store.state.cnf.rad.txf.maxE[1] / 1000}`"
v-slot="{ errors, pristine }"
>
<v-text-field
ref="txfLocCh2"
type="number"
v-model="values.upTxfLocCh2"
></v-text-field>
<span
v-if="errors.length > 0"
class="block-error block-error__main"
>{{ errors[0] }}</span>
</ValidationProvider>
....
<button type="submit" #click="formValid">Submit</button>
</form>
</ValidationObserver>
export default {
computed: {
formValid () {
// loop over all contents of the fields object and check if they exist and valid.
return Object.keys(this.fields).every(field => {
return this.fields[field] && this.fields[field].valid;
});
}
}
}
In devtools is message:
Error in render: "TypeError: Cannot convert undefined or null to object"
I use code from https://github.com/logaretm/vee-validate/issues/853 , but I do not know where is issue.
Can I ask for help?

V-select issue in Vuetify 3

I'm using Vuetify 3.0.0-beta.0 ~ for my project (because it is the only version that supports vue3), and having a bit weird issue
I want to implement the same thing as described there https://codepen.io/reijnemans/pen/vYNadMo?editors=1010 with v-select involved, so I was needed to use Vuetify
copied snippet
<v-select
:items="items"
label="Standard"
>
<template v-slot:selection="{ item, index }">
<img :src="item.image">{{ item.name }}</template>
</template>
<template v-slot:item="{ item }">
<img :src="item.image">{{ item.name }}</template>
</v-select>
My Component:
<template>
<div class="resourceSelectors">
<v-col cols="10" lg="4" class="mx-auto">
<div class="text-center">
<h2 class="indigo--text" style="margin-bottom: 30px">Some Test H2</h2>
</div>
<v-col class="d-flex" cols="12" sm="6">
<v-select
:items="items"
label="Standard">
<template v-slot:selection="{ item }">
<img :src="item.image">{{ item.name }}
</template>
<template v-slot:item="{ item }">
<img :src="item.image">{{ item.name }}
</template>
</v-select>
</v-col>
</v-col>
</div>
</template>
<script>
import { mapState } from "vuex";
/* eslint-disable */
export default {
name: "testComponent",
data() {
return {
// hardware Configuration Validation Rules
items: [
{ name: 'Foo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Bar', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Hoo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'},
{ name: 'Coo', image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'}],
}
}}
When I'm trying to run the above component I always get this weird error Failed setting prop "type" on <select>: value text is invalid. TypeError: Cannot set property type of #<HTMLSelectElement> which has only a getter,
Did anyone faced similar issue before?
In Vuetify 3, you need some workarounds to style the items in v-select, because the item slot resets the entire styling.
You should use the menu-props, with it you can pass props through to the v-menu component. It accepts an object with anything from /api/v-menu. This allows you to close the field on click.
In the item slot, you should use a v-list-item with an #click property to set the model.
I made an example here with a selection of symbols:
<script setup>
const symbols = [
'ab-testing',
'abacus',
'account',
'account-alert',
]
const form = { symbol: '', }
</script>
<template>
<v-select
v-model="form.symbol"
:items="symbols"
label="Symbol"
:prepend-inner-icon="'mdi-'+form.symbol"
:menu-props="{
closeOnClick: true,
closeOnContentClick: true,
}"
>
<template v-slot:selection="{ item, index }">
{{ item.value }}
</template>
<template v-slot:item="{ item, index }">
<v-list-item
:title="item.title"
:prepend-icon="'mdi-'+item.title"
#click="form.symbol = item.title"
>
</v-list-item>
</template>
</v-select>
</template>
I hope it helps you.
I couldn't find correct solution but I just wanted to share what I did about scoped slot. I think we should use item.raw to access name and image. And the next problem is how to make it clickable to trigger select event that I didn't know yet :(
const { createApp } = Vue
const { createVuetify } = Vuetify
const vuetify = createVuetify()
const app = createApp({
data() {
return {
value: null,
items: [
{
name: 'Foo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Bar',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Hoo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
},
{
name: 'Coo',
image: 'https://www.gravatar.com/avatar/b17065ea1655f1e3283aac8d8fc16019?s=48&d=identicon&r=PG'
}
]
}
}
});
app.use(vuetify).mount('#app');
<link href="https://cdn.jsdelivr.net/npm/vuetify#3.0.0-beta.9/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#3.0.0-beta.9/dist/vuetify.min.js"></script>
<div id="app">
<div class="resourceSelectors">
<v-col cols="10" lg="4" class="mx-auto">
<div class="text-center">
<h2 class="indigo--text" style="margin-bottom: 30px">Some Test H2</h2>
</div>
<v-col class="d-flex" cols="12" sm="6">
<v-select
v-model="value"
:items="items"
item-title="name"
item-value="name"
label="Standard">
<template v-slot:item="{item}">
<v-list-item
:prepend-avatar="item.raw.image"
:title="item.raw.name"
/>
</template>
</v-select>
</v-col>
</v-col>
</div>
</div>

Vee-validate - [Vue warn]: Failed to resolve directive: validate

I want to validate text fields, trying below code :
<input v-validate="result.val=='Required' ? 'required' : ''" v-model="required" :name="f_name" type="text"/>
but getting this error:
app.js:48089 [Vue warn]: Failed to resolve directive: validate
Trying this:
<ValidationProvider name="phone" :rules="required" v-slot="{ errors }">
<input class="form-control" :name="phone" type="text" v-model="form.phone"/>
</ValidationProvider>
According to the migration guide this directive is removed in v3.x :
Fields that had the v-validate directive needs to be wrapped by ValidationProvider component now, and they need to use v-model to properly tag themselves for vee-validate.
So this:
<input type="text" name="field" v-validate="'required'">
<span>{{ errors.first('field') }}</span>
Will be re-written as this:
<ValidationProvider name="field" rules="required" v-slot="{ errors }">
<input type="text" v-model="value">
<span>{{ errors[0] }}</span>
</ValidationProvider>
Your code should be like :
<ValidationProvider name="f_name" :rules="result.val=='Required' ? 'required' : ''" v-slot="{ errors }">
<input v-model="required" :name="f_name" type="text"/>
</ValidationProvider>
You should add this to main.js :
import { ValidationProvider } from 'vee-validate';
Vue.component('ValidationProvider', ValidationProvider);
If you are not using a bundler and using vee-validate in the browser or from a CDN:
<script>
// ...
Vue.component('validation-provider', VeeValidate.ValidationProvider);
// ...
</script>

Validation Required in Vue

I'm using vee-validate in my VueJS and I wonder how can i add a validation that if form.order == 1 then the it would be required
<ValidationProvider rules="v-if="form.order == 1 ? required: ''" v-slot="{ errors }" name="Entity">
<v-col md="4">
<v-text-field
label="First Name"
v-model="form.first_name"
outlined
hide-details="auto"
:error-messages="errors[0]"
></v-text-field>
</v-col>
</ValidationProvider>
May I suggest you move #Phymo's answer into a computed property so you keep your template clean, readable, and extendable. that way, you can swap the implementation anytime. i.e.
<template>
<ValidationProvider :rules="applyRules" v-slot="{ errors }" name="Entity">
<v-col md="4">
<v-text-field
label="First Name"
v-model="form.first_name"
outlined
hide-details="auto"
:error-messages="errors[0]"
></v-text-field>
</v-col>
</ValidationProvider>
</template>
<script>
export default {
data: () => ({
form: {
// form structure
}
}),
computed: {
applyRules() {
return this.form.order === 1 ? 'required' : ''
}
}
}
</script>
try this.
:rules="form.order == 1 ? 'required' : ''"

Vee Validate 3.0 custom classes not applied

From the docs, I think I need to use configure to add custom classes to my validated fields, but I can't get it to work.
This is what I have so far...
import { extend, configure, localize } from 'vee-validate'
import { required, min, max } from 'vee-validate/dist/rules'
import en from 'vee-validate/dist/locale/en.json'
// Install rules
extend('required', required)
extend('min', min)
extend('max', max)
// Install classes
configure({
classes: {
valid: 'is-valid',
invalid: 'is-invalid'
}
})
// Install messages
localize({
en
})
And in my view....
<ValidationObserver ref="observer" v-slot="{ invalid }" tag="form" #submit.prevent="checkRef()">
<div class="form-group">
<label for="reference">Reference</label>
<ValidationProvider rules="required|max:20" name="reference" v-slot="{ errors }">
<input maxlength="20" name="reference" v-model="ref" id="reference" class="form-control"/>
<span class="warning">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<button #click="checkRef" class="btn btn-primary app-button">Check Reference</button>
</ValidationObserver>
When I click the button, I see the error message but I don't get the 'in-invalid' class applied to my field.
What am I doing wrong?
VeeValidate does not apply the classes automatically anymore, since v3 you now must bind it yourself. Like errors you can extract classes from the slot props and apply it to your input:
<ValidationProvider rules="required|max:20" name="reference" v-slot="{ errors, classes }">
<input maxlength="20" name="reference" v-model="ref" id="reference" class="form-control" :class="classes" />
<span class="warning">{{ errors[0] }}</span>
</ValidationProvider>