Simple, lightweight model-based validation library for Vue.js applications
—
System for creating custom validation functions with parameter metadata support, enabling reusable and configurable validation logic.
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>;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
}
}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')
}
}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 }
}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
}
}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
}
}
})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 []
}
}
}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
}
}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