Skip to content

Complex Validation Patterns ​

This guide covers advanced validation scenarios that go beyond simple field validation.

Conditional Validation ​

For basic conditional validation patterns, like making fields required based on other field values, see the Common Validation Patterns guide.

Here's an example of more complex conditions:

javascript
const validator = factory.make({
  'subscription': 'required|in_list:basic,premium',
  'storage_gb': 'required|integer|min:5',
  'max_users': 'required_if:subscription,premium|integer|min:5'
})

Interdependent Field Validation ​

When the validation rule for one field depends on the value of another field, you can use custom validation functions:

javascript
const validator = factory.make({
  'discount_type': 'required|in_list:percentage,fixed',
  'discount_value': [
    { name: 'required', rule: new RequiredRule() },
    { name: 'number', rule: new NumberRule() },
    { 
      name: 'max',
      rule: new FunctionBasedRule((value, path, datasource) => {
        const type = datasource.discount_type
        const price = datasource.price
        
        if (type === 'percentage') {
          return Number(value) <= 100
        } else {
          return Number(value) <= Number(price)
        }
      })
    }
  ]
})

Dynamic Array Validation ​

This example shows how to validate array items with rules that depend on properties of each item:

javascript
const validator = factory.make({
  // Product validation
  'products.*.sku': 'required|matches:^[A-Z]{2}\\d{6}$',
  'products.*.name': 'required|min_length:3',
  'products.*.type': 'required|in_list:digital,physical,service',
  'products.*.price': 'required|number|min:0',
  'products.*.categories.*.': 'required|min_length:2',
  
  // Quantity validation based on product type
  'products.*.quantity': [
    { name: 'required', rule: new RequiredRule() },
    { name: 'integer', rule: new IntegerRule() },
    { 
      name: 'max',
      rule: new FunctionBasedRule((value, path, datasource) => {
        // Extract product index from path
        const match = path.match(/products\[(\d+)\]/)
        if (!match) return true
        
        const index = match[1]
        const type = datasource.products[index].type
        
        // Different maximum quantities by type
        const maxQuantities = {
          digital: 5,
          physical: 10,
          service: 1
        }
        
        return Number(value) <= (maxQuantities[type] || 999)
      })
    }
  ]
})

MIT Licensed