Versions
Describe the bug
Since version 3.3.0, when I'm using french localization and 2 fields bound together using the required_if rule, I now get such kind of validation errors:
Le champ mySecondField est obligatoire lorsque function (crossTable) { var val = crossTable[value]; return castFn ? castFn(val) : val; } possède cette valeur
Expected behavior
In version 3.2.5 and below, error messages were correctly displayed:
Le champ mySecondField est obligatoire lorsque myFirstField possède cette valeur
Reverting back to 3.2.5 solves the problem for me.
Desktop (please complete the following information):
I cannot seem to reproduce it, can you please create a minimal example for this issue?
It could be related to #2716 in 7cbb13d077b77f015a6f9347e08f66ef90600068
Hi,
I've extracted and refactored some code from my form, so you have some example.
Click inside and outside the input field named "First field" (leaving it blank) and you'll get following error message:
Le champ First field est obligatoire lorsque function (crossTable) { var val = crossTable[value]; return castFn ? castFn(val) : val; } possède cette valeur
<template>
<form id="app" class="needs-validation" novalidate @submit.prevent="">
<div>
<label>Selection</label>
<ValidationProvider
v-slot="{ errors }"
:rules="{ regex: /^[12]$/ }"
name="Selection"
vid="Selection"
>
<select v-model="Selection" required>
<option disabled value=""><Select></option>
<option value="1">First option</option>
</select>
<div v-if="errors.length > 0">
{{ errors[0] }}
</div>
</ValidationProvider>
</div>
<div v-show="Selection == 1">
<label>First field</label>
<ValidationProvider
v-slot="{ errors }"
:rules="
Selection == 1
? {
required_if: ['Selection', '1'],
}
: {}
"
name="First field"
>
<input
v-model.trim="FirstValue"
type="text"
pattern="[0-9]{6}[0-9abAB][0-9]{6}"
maxlength="13"
:disabled="Selection != 1"
/>
<div v-if="errors.length > 0">
{{ errors[0] }}
</div>
</ValidationProvider>
</div>
</form>
</template>
<script>
import {
extend,
localize,
ValidationProvider,
setInteractionMode,
} from 'vee-validate';
import fr from 'vee-validate/dist/locale/fr.json';
import * as rules from 'vee-validate/dist/rules';
setInteractionMode('eager');
localize('fr', fr);
Object.keys(rules).forEach((rule) => {
extend(rule, rules[rule]);
});
export default {
name: 'App',
components: {
ValidationProvider,
},
data() {
return {
Selection: '1',
FirstValue: '',
};
},
};
</script>
Same example on codesandbox ;)
Thanks for the demo, this is indeed a bug caused by handling an edge case in 7cbb13d077b77f015a6f9347e08f66ef90600068
As a workaround you could use an object instead of an array:
{
required_if: {
target: 'Selection',
values: ['1']
},
}
Or use the string format as a workaround for now, since it is tricky to handle both edge cases at the same time.
@logaretm, thank you very much for your answer and your workaround :)
For my existing code, I'll wait on a fix, I'm not in a hurry, version 3.2.5 works great for me ;)
I'm not even sure that fix 7cbb13d was really needed, if I understand well documentation Supplying Arguments, the example at #2716 should have been implemented this way:
data() {
return {
owner: "",
owners: [
[
{ owner: "a", … },
{ owner: "b", … },
…
]
]
};
},
or directly in
<validation-provider
:rules="{ required: true, notOneOf: [ owners ] }"
v-slot="{ errors }"
>
An array containing a single array (of any length) would have solved the problem in all cases, am I wrong?
I'm thinking about reverting it but would like to see if I can tackle both issues first.
The problem is that for the case when a rule first and the only argument is an array. This is confused with rules that have no named arguments and accepts infinite number of args like oneOf.
Currently, it is impossible to tell the two apart. The bug previously fixed caused the argument to be a single value instead of the passed array when it has a length of 1.
This was shortsighted when I decided to introduce named arguments to rules, I will see if this can be tackled in v3 and take it into account in v4.
Thank you for the explanation @logaretm ;)
I don't know if it's really easy to remove this kind of ambiguity without creating a new property for the very specific case of a custom rule accepting only one parameter whose value will be an "array of values".
With a new property (say "handleArrayAsSingleValue" for example), you would be able to revert 7cbb13d and handle gracefully #2716 ;)
Sorry if it's maybe a bad suggestion, I'm far from knowing vee-validate as well as you ;)
Not at all, this is a valid option but I try to limit the amount of configuration needed to make such caveats invisible to developers.
@logaretm This also affects custom rules that are expecting an array to be supplied. If the array only has item, the param is not passed as an array so we can't reliably do array type functions.
VeeValidate.extend('unique_value', {
params: ['values'],
validate: (value, { values = [] } = {}) => {
const valueCount = values.filter(arrayValue => arrayValue.toLowerCase() === value.toLowerCase()).length;
return {
valid: valueCount <= 1
}
},
message: `The {_field_} value must be unique`
});
usage:
{
unique_value: ['a'] // .filter() fails as the array is mapped to a string
unique_value: ['a', 'b'] // works as the array is passed, .filter() can do its thing.
}
Is there any workaround/ fix for this so that an array is always passed?
I decided to revert the commit as the current behavior breaks more than it fixes.