Documentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
User guide for creating powerful validation rules using expression-based validation in wizard steps.
Overview
Advanced Validation Expressions allow you to create complex validation rules that go beyond simple required/min/max checks. Using a JavaScript-like syntax, you can validate:
- Age requirements
- Date comparisons
- Conditional required fields
- Pattern matching
- Cross-field validation
- Custom business rules
Getting Started
Accessing Expression Validation
- Open a wizard template in the Builder
- Select a step
- Go to the Validation tab
- Click the Advanced Expressions sub-tab
Your First Expression
Let’s create a simple age validation:
This expression:
- Takes the
date_of_birth field value
- Calculates the age in years
- Checks if it’s 18 or older
Expression Syntax
Basic Structure
function(field_name) operator value
Operators
| Operator | Description | Example |
|---|
== | Equals | status == "active" |
!= | Not equals | status != "inactive" |
> | Greater than | age(dob) > 21 |
>= | Greater or equal | amount >= 100 |
< | Less than | quantity < 1000 |
<= | Less or equal | years_since(hire_date) <= 5 |
&& | Logical AND | a > 0 && b > 0 |
|| | Logical OR | a > 0 || b > 0 |
! | Logical NOT | !is_empty(email) |
Combining Expressions
Use && (AND) and || (OR) to combine multiple conditions:
// Both must be true
age(dob) >= 18 && !is_empty(email)
// Either can be true
is_empty(phone) || is_valid_phone(phone)
// Complex combination
(age(dob) >= 18 && is_employed) || has_guardian_consent
Available Functions
Date Functions
| Function | Description | Example |
|---|
age(date) | Years since date | age(date_of_birth) >= 18 |
years_since(date) | Years since date | years_since(hire_date) >= 1 |
months_since(date) | Months since date | months_since(start_date) >= 6 |
days_since(date) | Days since date | days_since(last_review) <= 365 |
is_before(date1, date2) | date1 < date2 | is_before(start_date, end_date) |
is_after(date1, date2) | date1 > date2 | is_after(hire_date, training_date) |
today() | Current date | is_before(deadline, today()) |
String Functions
| Function | Description | Example |
|---|
is_empty(value) | Check null/empty | !is_empty(email) |
is_not_empty(value) | Check has value | is_not_empty(email) |
len(value) | String length | len(name) >= 2 |
matches(value, pattern) | Regex match (safe) | matches(zip, "^\\d{5}$") |
starts_with(value, prefix) | Check prefix | starts_with(phone, "+1") |
ends_with(value, suffix) | Check suffix | ends_with(email, ".edu") |
contains(value, substring) | Check substring | contains(notes, "urgent") |
Validation Functions
| Function | Description | Example |
|---|
is_valid_email(value) | Email format | is_valid_email(email) |
is_valid_phone(value) | Phone format | is_valid_phone(phone) |
is_valid_ssn(value) | SSN format | is_valid_ssn(ssn) |
is_valid_zip(value) | US ZIP format | is_valid_zip(zip_code) |
Number Functions
| Function | Description | Example |
|---|
is_between(val, min, max) | Range check | is_between(age, 18, 65) |
Comparison Functions
| Function | Description | Example |
|---|
eq(a, b) | Equals | eq(status, "active") |
neq(a, b) | Not equals | neq(status, "closed") |
gt(a, b) | Greater than | gt(age, 18) |
gte(a, b) | Greater or equal | gte(score, 70) |
lt(a, b) | Less than | lt(quantity, 100) |
lte(a, b) | Less or equal | lte(price, 1000) |
Conditional Functions
| Function | Description | Example |
|---|
required_if(condition, field) | Conditional required | required_if(is_employed, employer_name) |
one_of(value, options) | Value in list | one_of(status, ["active", "pending"]) |
not_one_of(value, options) | Value not in list | not_one_of(role, ["admin", "super"]) |
all(a, b, ...) | All truthy | all(has_consent, is_adult) |
any(a, b, ...) | Any truthy | any(has_phone, has_email) |
not(value) | Logical NOT | not(is_locked) |
Common Patterns
Age Verification
// Must be 18 or older
age(date_of_birth) >= 18
// Must be between 18 and 65
is_between(age(date_of_birth), 18, 65)
// Under 18 requires guardian
age(date_of_birth) >= 18 || !is_empty(guardian_name)
Date Range Validation
// End date must be after start date
is_after(end_date, start_date)
// Event must be in the future
is_after(event_date, today())
// Must be within 90 days
days_since(submission_date) <= 90
Conditional Required Fields
// Employer required if employed
required_if(is_employed, employer_name)
// Phone OR email required
!is_empty(phone) || !is_empty(email)
// Address required if not same as billing
required_if(!same_as_billing, shipping_address)
// US phone format (10 digits)
matches(phone, "^\\d{10}$")
// ZIP code (5 or 9 digits)
matches(zip, "^\\d{5}(-\\d{4})?$")
// Strong password (8+ chars, number, special)
len(password) >= 8 && matches(password, "[0-9]") && matches(password, "[!@#$%]")
Cross-Field Validation
// Confirm password matches
password == confirm_password
// Total must equal sum of parts
total == (subtotal + tax)
// End date at least 30 days after start
days_since(start_date) >= 30 || is_after(end_date, start_date)
Creating Expression Rules
Step-by-Step
- Open Validation Panel: Select a step and click “Validation” tab
- Switch to Advanced: Click “Advanced Expressions” sub-tab
- Add Rule: Click “Add Expression Rule”
- Write Expression: Enter your validation expression
- Set Error Message: Define the message shown when validation fails
- Set Timing: Choose when to validate (on change, blur, or submit)
- Test: Use the Test Runner to verify
Rule Properties
| Property | Description |
|---|
| Expression | The validation logic |
| Error Message | Shown when validation fails |
| Timing | When to run: on_change, on_blur, on_submit |
| Priority | Order of execution (lower runs first) |
| Enabled | Toggle rule on/off without deleting |
Testing Expressions
Using the Test Runner
- Click Test Expressions button
- Enter sample values for each field
- Click Run Tests
- View pass/fail results for each rule
Test Runner Features
- Field Inputs: Auto-generated from step fields
- Quick Fill: Sample data suggestions
- Results Panel: Shows which rules pass/fail
- Error Preview: See exact error messages
Testing Tips
- Test both valid and invalid inputs
- Test edge cases (empty, null, boundaries)
- Test with realistic data
- Verify error messages are helpful
Error Messages
Writing Good Messages
❌ Bad: “Invalid”
✅ Good: “Date of birth indicates you must be at least 18 years old”
❌ Bad: “Required”
✅ Good: “Employer name is required when employment status is ‘Employed‘“
Message Variables
You can reference field values in messages (coming soon):
"Age {{age(date_of_birth)}} does not meet the minimum requirement of 18"
Best Practices
Expression Design
- Keep It Simple: Break complex rules into multiple expressions
- Be Specific: Target specific fields, not entire forms
- Handle Empty: Always consider null/empty cases
- Use Parentheses: Make precedence explicit
- Timing Matters: Use
on_submit for expensive validations
- Avoid Redundancy: Don’t repeat standard validations
- Order by Priority: Put quick-fail checks first
Maintenance
- Document Rules: Use clear error messages as documentation
- Group Related Rules: Keep related validations together
- Test After Changes: Always re-test after modifications
- Version Control: Track changes in template versions
Healthcare & PHI Compliance
PHI Field Naming Guidelines
When creating validation expressions that may touch PHI/PII:
- Use Generic Field Names: Prefer
patient_id, resident_id, client_id over revealing field names
- Avoid Revealing Names: Never use field names that expose sensitive data types (avoid
ssn, medical_record_number, diagnosis_code)
Expression Audit Requirements
All expressions touching PHI fields must be:
- Reviewed by a compliance officer before deployment
- Logged for creation/modification with user ID and timestamp
- Never log actual PHI values - only log field references and expression text
Error Message Rules (Critical)
Functions like age(), matches(), required_if() must:
- Never include actual field values in error messages
- Use generic messages: “Age requirement not met” not “Your age of 17 does not meet…”
- Avoid revealing field contents in validation failures
Timing Recommendations for PHI
- Use
on_submit: For PHI field validations to minimize data exposure during typing
- Avoid
on_change: Real-time validation can increase attack surface
Access Control
- Only users with appropriate permissions should edit expressions
- Expression editing should be restricted to form administrators
- Implement retention policies for expression audit logs (recommended: 7 years for healthcare)
Security Considerations
Safe by Design
Expression validation is sandboxed:
- No
eval() or code execution
- No access to global objects
- No network requests
- No file system access
What’s Blocked
- JavaScript code injection
- Function definitions
- Variable assignments
- External references
What’s Allowed
- Field references by name
- Approved validation functions
- Operators (comparison, logical)
- Literal values (strings, numbers, booleans)
Troubleshooting
Common Errors
| Error | Cause | Fix |
|---|
| ”Unknown function” | Typo or unsupported function | Check function name spelling |
| ”Unknown field” | Field name not found | Verify field name property |
| ”Syntax error” | Malformed expression | Check operators and parentheses |
| ”Type mismatch” | Wrong value type | Ensure correct field types |
Debugging Tips
- Simplify: Reduce to smallest failing case
- Test Runner: Use to isolate issues
- Check Field Names: Match exactly (case-sensitive)
- Review Syntax: Watch for missing quotes/parentheses
See Also