logaretm / vee-validate

✅ Painless Vue forms
https://vee-validate.logaretm.com/v4
MIT License
10.75k stars 1.26k forks source link

Using global and local validators together #4058

Open sttrbl opened 1 year ago

sttrbl commented 1 year ago

Hi!

It is now possible to use either global validators in string and object syntax, or local validators in functional syntax.

<Field rules="required" />

<Field
  :rules="[
    (value) => value || 'Error',
    (value) => value > 2 || 'Error 2',
  ]"
/>

But is it somehow possible to use local and global validators together in :rules value? If not, then it would be cool to add such an opportunity, because personally in our project such a need arises often.

<!-- Something like this -->
<Field
  :rules="[
    'required',
    (value) => value || 'Error',
    (value) => value > 2 || 'Error 2',
  ]"
/>

Thanks!

logaretm commented 1 year ago

Not possible at the moment. However, I don't think it needs much work to get it working. I will see what I can do.

isaackearl commented 1 year ago

Yes this would be very useful. I tried to do this today and it didn't work. If it sees one "Callable" rule in the array, then it tries to call all of them, which blows up for the global rules. I tried something like this:

:rules="['required', 'email', validateEmail]"

and it throws an error "Uncaught (in promise) TypeError: rule is not a function"

because it tries to call "required" (string) as a function.

cas-technology commented 1 year ago

Isn't it 'better' to use a semi-standard already set by Vue in classes? e.g:

<label
    class="class-one class-two"
    :class="[
        computedClass,
        buttonClass,
        value === selectedValue || selectedValue === true
            ? 'checked'
             : '',
        ]"
/>

so something like this:

<Field
  rules='required|email'
  :rules="[
    (value) => value || 'Error',
    (value) => value > 2 || 'Error 2',
  ]"
/>
logaretm commented 1 year ago

@cas-technology Some rules do receive false as an argument, so turning them off with falsy values is risky.

mastrayer commented 3 months ago

I have added a global rule to execute local functions.

interface FieldValidationMetaInfo {
  field: string;
  name: string;
  label?: string;
  value: unknown;
  form: Record<string, unknown>;
  rule?: {
    name: string;
    params?: Record<string, unknown> | unknown[];
  };
}

type ValidationRuleFunction<TValue = unknown, TParams = unknown[] | Record<string, unknown>> = (
  value: TValue,
  params: TParams,
  context: FieldValidationMetaInfo
) => boolean | string | Promise<boolean | string>;

type Params =
  | {
      rule: ValidationRuleFunction;
    }
  | [rule: ValidationRuleFunction, ...params: unknown[]];

const local: ValidationRuleFunction<unknown, Params> = (value, params, context) => {
  if (Array.isArray(params)) {
    const [rule, ...otherParams] = params;
    return rule(value, otherParams, context);
  } else {
    const { rule, ...otherParams } = params;
    return rule(value, otherParams, context);
  }
};

//////////////////////////

defineRule('local', local);

<Field :rules="{
  local: localValidationRule,
  globalRule: true,
}" />

<Field :rules="{
  local: {
    rule: localValidationRule,
    otherParams: {},
  },
  globalRule: true,
}" />