Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add when built-in validator (or helper) #1213

Open
renatodeleao opened this issue Oct 4, 2023 · 1 comment
Open

feat: add when built-in validator (or helper) #1213

renatodeleao opened this issue Oct 4, 2023 · 1 comment

Comments

@renatodeleao
Copy link

renatodeleao commented Oct 4, 2023

The problem

Conditional validation is pretty common problem, that's why we have requiredIf and requiredUnless. The problem is that they only work for required validation. If we want other validators to be conditionally executed as well I have to write custom validator wrappers, which is a bit cumbersome. In my app, since I've done it so many times, I end-up writing a wrapper that I'm now sharing with you.

Solution

a when validator, that would work just like requiredIf but instead accepted any validator as an argument.

The code

import { toValue } from 'vue'

/**
 *  It's like requiredIf but any validator, in fact
 * `when(condition)(required) === requiredIf(condition)`
 *
 * @typedef {import('@vuelidate/core').ValidatorFn} ValidatorFn
 * @typedef {import('@vuelidate/core').ValidationRule} ValidationRule
 *
 * @param {import('vue').MaybeRefOrGetter | ValidatorFn} refOrConditionFn
 * @returns {(ValidationRule) => ValidationRule}
 */
export const when = (refOrConditionFn) => (validator) => {
  return {
    ...validator,
    $validator: (...args) => {
      const doValidate = typeof refOrConditionFn === 'function'
       ? refOrConditionFn(...args)
       : toValue(refOrConditionFn)

      return doValidate ? validator.$validator(...args) : true
    }
  }
}

Note: The code could also be adapted to accept a validator function instead of a normalized validator as it is now.

EDIT: removed optional chaining for shorter output.

Usage

// inline
const rules = {
    x: 'something',
    y: when((_, siblings) => siblings.x === 'something')(myValidator),
    z: when((_, siblings) => siblings.x === 'something')(myOtherValidator),
}

// wrap it to DRY it up
const whenXIsSomething = when((_, siblings) => siblings.x === 'something')
const rules = {
    x: 'something',
    y: whenXIsSomething(myValidator),
    z: whenXIsSomething(myOtherValidator),
}

Additional context

I understand that this can be achieved in userland pretty easily, but would be nice to have baked-in support.

I believe this is useful, otherwise requiredIf and requiredUnless wouldn't be a thing. In fact, these validators could be rewritten using the when validator under the hood.

const rules = {
   y: requiredIf((_, siblings) => siblings.x === 'something'), 
   x: when((_, siblings) => siblings.x === 'something')(required)  // same as above
}
export const requiredIf = (condition) => when(condition)(required)

Since when returns a function and not a validator, maybe this could be categorised as a helper like helpers.withMessage to be more consistent with the current API

@metalsadman
Copy link

looks great

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants