Form Validation
Form validation ensures data quality by checking that user input meets required criteria before processing. Forms support multiple validation layers for comprehensive data validation.
Validation Layers
Forms provide three layers of validation:
1. Client-Side Validation
Where: Browser (immediate feedback)
When: As user types or on field blur
Purpose: Provide instant feedback, improve user experience
Types: - Mandatory field checks - Input type validation (email, number, date) - Regex pattern matching - Min/max length - Min/max value - Custom script validation
Benefits: - Instant feedback - No server round-trip - Better user experience - Reduced server load
Limitations: - Can be bypassed - Cannot access server data - Limited to simple checks
2. Server-Side Validation
Where: Server (security layer)
When: On form submission
Purpose: Security, server-side checks
Types: - Mandatory field verification - Data type validation - Format validation - Security checks
Benefits: - Cannot be bypassed - Secure validation - Consistent enforcement
Limitations: - Requires server round-trip - Slower feedback - Less interactive
3. ETL-Based Validation
Where: Server (business logic layer)
When: On form submission, before processing
Purpose: Complex business rules, database lookups
Types: - Business rule validation - Database lookups - Cross-field validation - External system checks - Complex calculations
Benefits: - Access to full data - Complex logic - Reusable validation chains - Integration with business systems
Limitations: - Slowest feedback - Most complex to implement
Client-Side Validation
Mandatory Fields
Mark fields as required:
- Select component in Form Designer
- Check Mandatory Field property
- Field displays with red indicator
- Cannot submit until filled
Example:
Text Input: employeeName
├── Label: "Employee Name"
├── Mandatory Field: ✓
└── User must fill before submit
Input Type Validation
Use appropriate input types:
Email:
Text Input: email
├── Label: "Email Address"
├── Input Type: email
├── Mandatory Field: ✓
└── Validates email format
Number:
Text Input: age
├── Label: "Age"
├── Input Type: number
├── Min Value: 18
├── Max Value: 100
└── Validates numeric range
Date:
Date Input: startDate
├── Label: "Start Date"
├── Mandatory Field: ✓
└── Validates date format
Regex Validation
Use Text Regex Input for custom patterns:
Phone Number:
Text Regex Input: phone
├── Label: "Phone Number"
├── Regex: ^\d{3}-\d{3}-\d{4}$
├── Placeholder: "555-123-4567"
└── Validates phone format
Employee ID:
Text Regex Input: employeeId
├── Label: "Employee ID"
├── Regex: ^EMP-\d{5}$
├── Placeholder: "EMP-12345"
└── Validates ID format
Script Validation
Use scripts for complex client-side validation:
After Build Script:
// Validate that end date is after start date
const startDate = form.getField('startDate');
const endDate = form.getField('endDate');
endDate.addValidator((value) => {
if (value && startDate.value) {
if (new Date(value) <= new Date(startDate.value)) {
return "End date must be after start date";
}
}
return null; // Valid
});
ETL-Based Validation
Creating Validation Chainsets
Steps:
- Create ETL chainset
- Add validation logic steps
- Add Validation Endpoint step (marker)
- Chainset appears in form’s Validator dropdown
Example Chainset:
Validate Employee Form
├── Step 1: Check email format
├── Step 2: Check email uniqueness
├── Step 3: Check employee ID exists
├── Step 4: Check hire date valid
├── Step 5: Validation Endpoint
└── Returns validationIssues array
Validation Issues Format
Return errors in this format:
{
"validationIssues": [
{
"field": "email",
"message": "Email address is already in use"
},
{
"field": "hireDate",
"message": "Hire date cannot be in the future"
}
]
}
Requirements: - field - Must match component ID - message - User-friendly error message
Form-Level Validation
Configure for entire form:
- Select root in form structure
- Find Validator property
- Select validation chainset
- Validation runs on submission
Page-Level Validation
Configure for specific page:
- Select Page component
- Find Validator property
- Select validation chainset
- Validation runs when leaving page
Common Validation Patterns
Pattern 1: Email Uniqueness
Check if email already exists:
Validate Email Uniqueness
├── Step 1: Extract email from form
│ └── email = record.email
├── Step 2: Query user database
│ └── SELECT * FROM users WHERE email = ?
├── Step 3: Check if exists
│ └── If found, add validation issue
├── Step 4: Validation Endpoint
└── Return validation result
Pattern 2: Date Range Validation
Validate start and end dates:
Validate Date Range
├── Step 1: Get dates
│ ├── startDate = record.startDate
│ └── endDate = record.endDate
├── Step 2: Check end > start
│ └── If not, add error
├── Step 3: Check not in past
│ └── If past, add error
├── Step 4: Check within 1 year
│ └── If too far, add error
├── Step 5: Validation Endpoint
└── Return validation issues
Pattern 3: Budget Validation
Check against available budget:
Validate Budget
├── Step 1: Get amount and budget code
├── Step 2: Query budget database
│ └── SELECT remaining FROM budgets WHERE code = ?
├── Step 3: Compare amount to remaining
├── Step 4: If exceeds, add validation issue
│ ├── field: "amount"
│ └── message: "Exceeds available budget ($X remaining)"
├── Step 5: Validation Endpoint
└── Return validation result
Pattern 4: Cross-Field Validation
Validate dependent fields:
Validate Leave Request
├── Step 1: Get leave type
├── Step 2: If type == "sick"
│ └── Check medical certificate attached
│ └── If not, add error
├── Step 3: If type == "annual"
│ └── Check leave balance
│ └── If insufficient, add error
├── Step 4: Validation Endpoint
└── Return validation issues
Pattern 5: External System Validation
Validate against external API:
Validate Address
├── Step 1: Get address fields
├── Step 2: Call address verification API
│ └── POST to external service
├── Step 3: Check response
├── Step 4: If invalid, add validation issue
│ ├── field: "address"
│ └── message: "Address not found"
├── Step 5: Validation Endpoint
└── Return validation result
Pattern 6: Business Hours Validation
Check if date/time is within business hours:
Validate Appointment Time
├── Step 1: Get appointment date and time
├── Step 2: Check if weekend
│ └── If yes, add error
├── Step 3: Check if business hours (9am-5pm)
│ └── If no, add error
├── Step 4: Check if holiday
│ └── Query holiday database
│ └── If holiday, add error
├── Step 5: Validation Endpoint
└── Return validation issues
Pattern 7: Conditional Validation
Different validation based on field values:
Validate Order
├── Step 1: Get order type
├── Step 2: If type == "wholesale"
│ └── Check minimum quantity (100)
│ └── If less, add error
├── Step 3: If type == "retail"
│ └── Check maximum quantity (10)
│ └── If more, add error
├── Step 4: Validation Endpoint
└── Return validation issues
Pattern 8: Lookup Validation
Validate by looking up related data:
Validate Employee ID
├── Step 1: Get employee ID
├── Step 2: Query employee database
│ └── SELECT * FROM employees WHERE id = ?
├── Step 3: If not found
│ └── Add validation issue
├── Step 4: If found
│ └── Add employee details to form data
│ └── Store in elxPublic for display
├── Step 5: Validation Endpoint
└── Return validation result
Validation Error Display
Error Messages
Display validation errors clearly:
Field-Level Errors: - Appear below the field - Red text with icon - Specific to the field - Cleared when field is corrected
Form-Level Errors: - Appear at top of form - Summary of all errors - Link to fields with errors - Cleared when all fields valid
Scroll to Error
Enable automatic scrolling to errors:
- Select root component
- Check Scroll To Error property
- On validation error, form scrolls to first error
Custom Error Messages
Set custom messages in validation chainsets:
{
"validationIssues": [
{
"field": "email",
"message": "This email is already registered. Please use a different email or login to your existing account."
}
]
}
Best Practices: - Be specific about the problem - Suggest how to fix it - Use friendly, helpful tone - Avoid technical jargon
Validation Best Practices
1. Validate Early
Use client-side validation for immediate feedback on: - Mandatory fields - Format validation - Simple range checks
2. Validate Securely
Always use server-side validation for: - Security-critical checks - Data integrity - Business rules
3. Provide Clear Messages
- Be specific about what’s wrong
- Explain how to fix it
- Use friendly language
- Avoid blame
Good: “Email address is already registered. Please use a different email.”
Bad: “Invalid input.”
4. Validate Progressively
- Client-side: Instant feedback
- Server-side: Security check
- ETL: Business rules
5. Don’t Duplicate Logic
- Use ETL validation for complex rules
- Reuse validation chainsets
- Keep client-side simple
6. Test Thoroughly
Test validation with: - Valid data - Invalid data - Edge cases - Boundary values - Missing data - Malformed data
7. Handle Errors Gracefully
- Don’t lose user data on error
- Preserve form state
- Allow easy correction
- Provide help
8. Consider User Experience
- Don’t validate too early (on blur, not on keypress)
- Don’t show all errors at once
- Focus on first error
- Allow submission attempt
Troubleshooting
Validation Not Running
Check: - Chainset has Validation Endpoint step - Chainset selected in form Validator property - Form submission triggering validation - User has permission to execute chainset
Errors Not Displaying
Check: - Errors in validationIssues array - Field IDs match component IDs exactly - Error format is correct (field, message) - No JavaScript errors in console
Client Validation Bypassed
Solution: - Always use server-side validation - Never trust client-side only - ETL validation is server-side
Validation Too Slow
Solutions: - Optimize database queries - Use indexes - Cache frequently used data - Simplify validation logic - Consider async validation
Validation Errors Confusing
Solutions: - Rewrite error messages - Add examples - Provide help links - Show valid format
Complete Validation Example
Leave Request Validation
Client-Side:
Form Components:
├── startDate (Date Input, Mandatory)
├── endDate (Date Input, Mandatory)
├── leaveType (Select, Mandatory)
├── reason (Text Area, Mandatory)
└── documents (Attachments, Conditional)
Script Validation:
- End date must be after start date
- Dates cannot be in past
ETL Validation:
Validate Leave Request Chainset
├── Step 1: Validate Date Range
│ ├── Check endDate > startDate
│ ├── Check dates not in past
│ └── Check dates within 1 year
│
├── Step 2: Check Leave Balance
│ ├── Get employee and leave type
│ ├── Query leave balance
│ ├── Calculate requested days
│ └── Verify balance sufficient
│
├── Step 3: Check Blackout Dates
│ ├── Query blackout periods
│ ├── Check for overlap
│ └── If overlap, add error
│
├── Step 4: Check Medical Certificate
│ ├── If leaveType == "sick"
│ ├── Check documents attached
│ └── If missing, add error
│
├── Step 5: Check Manager Availability
│ ├── Lookup manager
│ ├── Check manager not on leave
│ └── If unavailable, add warning
│
└── Step 6: Validation Endpoint
└── Return all validation issues
Result: - Comprehensive validation - Clear error messages - Good user experience - Data integrity ensured
Next Steps
- ETL Integration - Learn ETL validation
- Complete Example - See validation in action
- Form Designer - Configure validation
- Core Concepts - Understand validation architecture