CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vuelidate

Simple, lightweight model-based validation library for Vue.js applications

Pending
Overview
Eval results
Files

custom-validators.mddocs/

Custom Validators and Parameters

System for creating custom validation functions with parameter metadata support, enabling reusable and configurable validation logic.

Capabilities

withParams Function

Higher-order function for adding parameter metadata to validators, enabling parameter inspection and enhanced error reporting.

/**
 * Adds parameter metadata to a validator function
 * @param params - Object containing parameter metadata
 * @param validator - Validator function to wrap
 */
function withParams(
  params: object,
  validator: (value: any, parentVm?: any) => boolean | Promise<boolean>
): (value: any, parentVm?: any) => boolean | Promise<boolean>;

/**
 * Closure-based parameter addition for dynamic parameter scenarios
 * @param closure - Function that receives addParams function and returns validator
 */
function withParams(
  closure: (addParams: (params: object) => void) => (value: any, parentVm?: any) => boolean | Promise<boolean>
): (value: any, parentVm?: any) => boolean | Promise<boolean>;

Creating Custom Validators

Simple Custom Validators

Basic custom validators without parameters.

Usage:

import { withParams } from 'vuelidate'

// Simple validator without parameters
const strongPassword = (value) => {
  if (!value) return true // allow empty, combine with required if needed
  
  const hasUpper = /[A-Z]/.test(value)
  const hasLower = /[a-z]/.test(value)
  const hasNumber = /\d/.test(value)
  const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(value)
  
  return hasUpper && hasLower && hasNumber && hasSpecial
}

// Usage in component
validations: {
  password: {
    required,
    strongPassword
  }
}

Parameterized Custom Validators

Custom validators that accept configuration parameters.

Usage:

import { withParams } from 'vuelidate'

// Validator factory with parameters
const customMinLength = (min) => withParams(
  { type: 'customMinLength', min },
  (value) => {
    return !value || value.length >= min
  }
)

// Date range validator
const dateRange = (startDate, endDate) => withParams(
  { type: 'dateRange', startDate, endDate },
  (value) => {
    if (!value) return true
    const date = new Date(value)
    return date >= new Date(startDate) && date <= new Date(endDate)
  }
)

// Usage in component
validations: {
  username: {
    customMinLength: customMinLength(3)
  },
  eventDate: {
    dateRange: dateRange('2024-01-01', '2024-12-31')
  }
}

Contextual Validators

Validators that access component context and other properties.

Usage:

import { withParams } from 'vuelidate'

// Validator that accesses other component data
const dependsOnOtherField = withParams(
  { type: 'dependsOnOtherField' },
  function(value, parentVm) {
    // Access other properties via parentVm or this
    const otherValue = parentVm.otherField
    return !value || value !== otherValue
  }
)

// Age-based validation
const ageBasedValidation = withParams(
  { type: 'ageBasedValidation' },
  function(value, parentVm) {
    const age = parentVm.age
    if (age < 18) {
      return !value || value.length <= 10 // shorter value for minors
    }
    return !value || value.length <= 50 // longer value for adults
  }
)

// Usage in component
validations: {
  field1: { dependsOnOtherField },
  comment: { ageBasedValidation }
}

Async Custom Validators

Validators that perform asynchronous operations like API calls.

Usage:

import { withParams } from 'vuelidate'

// Async username availability check
const uniqueUsername = withParams(
  { type: 'uniqueUsername' },
  async (value) => {
    if (!value) return true
    
    try {
      const response = await fetch(`/api/check-username?username=${value}`)
      const data = await response.json()
      return data.available
    } catch (error) {
      // Handle error - could return false or true depending on strategy
      return false
    }
  }
)

// Async email verification
const verifyEmail = withParams(
  { type: 'verifyEmail' },
  (value) => {
    if (!value) return true
    
    return new Promise((resolve) => {
      // Simulate API call
      setTimeout(() => {
        const isValid = value.includes('@') && !value.includes('spam')
        resolve(isValid)
      }, 1000)
    })
  }
)

// Usage in component
validations: {
  username: {
    required,
    uniqueUsername
  },
  email: {
    required,
    email,
    verifyEmail
  }
}

Closure-based Parameter Addition

Advanced parameter management using the closure form of withParams.

Usage:

import { withParams } from 'vuelidate'

// Complex validator with dynamic parameters
const complexValidator = withParams((addParams) => {
  return function(value, parentVm) {
    // Add different parameters based on conditions
    if (!value) {
      addParams({ type: 'complex', reason: 'empty' })
      return true
    }
    
    if (value.length < 5) {
      addParams({ type: 'complex', reason: 'tooShort', minLength: 5 })
      return false
    }
    
    if (!/^[a-zA-Z]/.test(value)) {
      addParams({ type: 'complex', reason: 'mustStartWithLetter' })
      return false
    }
    
    addParams({ type: 'complex', reason: 'valid' })
    return true
  }
})

// Validator with conditional sub-validations
const conditionalValidator = withParams((addParams) => {
  return function(value, parentVm) {
    const userType = parentVm.userType
    
    addParams({ type: 'conditional', userType })
    
    if (userType === 'admin') {
      addParams({ minLength: 10 })
      return !value || value.length >= 10
    } else {
      addParams({ minLength: 5 })
      return !value || value.length >= 5
    }
  }
})

Parameter Access

Accessing Validator Parameters

Parameters added via withParams are accessible through the validation state.

Usage:

// In component template or methods
export default {
  // ... component setup
  computed: {
    passwordErrors() {
      const validation = this.$v.password
      
      if (validation.$error) {
        const errors = []
        
        // Access parameters from custom validators
        if (!validation.customMinLength) {
          const params = validation.customMinLength.$params
          errors.push(`Minimum length is ${params.min} characters`)
        }
        
        if (!validation.strongPassword) {
          errors.push('Password must contain uppercase, lowercase, number, and special character')
        }
        
        return errors
      }
      
      return []
    }
  }
}

Parameter Inspection

Using parameters for dynamic error messages and UI behavior.

Usage:

// Generic error message generator
function generateErrorMessage(fieldName, validation) {
  for (const ruleName in validation) {
    if (ruleName.startsWith('$') || validation[ruleName]) continue
    
    const rule = validation[ruleName]
    const params = rule.$params
    
    if (params) {
      switch (params.type) {
        case 'minLength':
          return `${fieldName} must be at least ${params.min} characters`
        case 'dateRange':
          return `${fieldName} must be between ${params.startDate} and ${params.endDate}`
        case 'uniqueUsername':
          return `${fieldName} is already taken`
        default:
          return `${fieldName} is invalid`
      }
    }
  }
  
  return `${fieldName} is invalid`
}

// Usage in component
computed: {
  usernameError() {
    return this.$v.username.$error
      ? generateErrorMessage('Username', this.$v.username)
      : null
  }
}

Helper Utilities

Common Validator Patterns

Reusable patterns for building custom validators.

/**
 * Core required check utility (exported from validators/common)
 */
function req(value: any): boolean;

/**
 * Type-agnostic length utility (exported from validators/common)
 */
function len(value: any): number;

/**
 * Resolve referenced values from component (exported from validators/common)
 */
function ref(reference: string | Function, vm: any, parentVm: any): any;

/**
 * Regex-based validator template (exported from validators/common)
 */
function regex(type: string, expr: RegExp): (value: any) => boolean;

Usage:

import { withParams, helpers } from 'vuelidate'

const { req, len, ref, regex } = helpers

// Using helper utilities
const customRequired = withParams(
  { type: 'customRequired' },
  (value) => req(value)
)

const customLength = (min, max) => withParams(
  { type: 'customLength', min, max },
  (value) => {
    const length = len(value)
    return length >= min && length <= max
  }
)

const phoneNumber = regex('phoneNumber', /^\+?[\d\s\-\(\)]+$/)

const dependentField = (otherField) => withParams(
  { type: 'dependentField', otherField },
  function(value, parentVm) {
    const otherValue = ref(otherField, this, parentVm)
    return !value || value !== otherValue
  }
)

Install with Tessl CLI

npx tessl i tessl/npm-vuelidate

docs

collections.md

custom-validators.md

index.md

integration.md

validation-state.md

validators.md

tile.json