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:

  1. Select component in Form Designer
  2. Check Mandatory Field property
  3. Field displays with red indicator
  4. 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:

  1. Create ETL chainset
  2. Add validation logic steps
  3. Add Validation Endpoint step (marker)
  4. 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:

  1. Select root in form structure
  2. Find Validator property
  3. Select validation chainset
  4. Validation runs on submission

Page-Level Validation

Configure for specific page:

  1. Select Page component
  2. Find Validator property
  3. Select validation chainset
  4. 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:

  1. Select root component
  2. Check Scroll To Error property
  3. 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