---
name: validation-microflows
description: "Validation microflows for new/edit pages — attribute checks, feedback messages, and conditional validation chains. Use when a form needs input validation with messages shown against the fields."
---

# Validation Microflows Skill

This skill provides guidance for creating validation microflows in MDL that validate user input on NewEdit pages and provide feedback to users.

## When to Use This Skill

Use this skill when:
- Creating validation logic for NewEdit pages
- Implementing attribute validation with feedback messages
- Building conditional validation chains
- Creating action microflows that call validation microflows

> **Nanoflow validation:** The same patterns apply to nanoflows (`create nanoflow` instead of `create microflow`). Use nanoflows for client-side validation when server roundtrips are unnecessary — validation feedback renders instantly without a network call.

## The Validation Pattern

Mendix validation follows a two-microflow pattern:

1. **VAL_Entity_Action** - The validation microflow that:
   - Takes an entity object as parameter
   - Validates each required field
   - Shows validation feedback on invalid fields
   - Returns a Boolean indicating overall validity

2. **ACT_Entity_Action** - The action microflow that:
   - Calls the validation microflow
   - Only proceeds with save/commit if validation passes
   - Closes the page on success

## MDL Syntax

### VALIDATION FEEDBACK Statement

```mdl
validation feedback $VariableName/attributename message 'Error message';
```

With template arguments (for dynamic messages):
```mdl
validation feedback $VariableName/attributename message '{1}' objects [$MessageVariable];
```

### CLOSE PAGE Statement

```mdl
close page;
```

Or to close multiple pages:
```mdl
close page 2;
```

## Complete Example

### Validation Microflow (VAL_Car_NewEdit)

```mdl
/**
 * Validates a Car entity for NewEdit operations
 *
 * Performs validation on all required fields and displays
 * appropriate error messages to the user.
 *
 * @param $Car The Car entity to validate
 * @returns Boolean indicating if all validations passed
 */
create microflow MdlTemplates.VAL_Car_NewEdit (
  $Car: MdlTemplates.Car
)
returns boolean as $IsValid
folder 'OverviewPages'
begin
  -- Initialize validation flag
  declare $IsValid boolean = true;

  -- Validate Brand (required text field)
  if trim($Car/Brand) = '' then
    set $IsValid = false;
    validation feedback $Car/Brand message 'Brand is required';
  end if;

  -- Validate Model (required text field)
  if trim($Car/model) = '' then
    set $IsValid = false;
    validation feedback $Car/model message 'Model is required';
  end if;

  -- Validate Price (required, must be positive)
  if $Car/Price = empty then
    set $IsValid = false;
    validation feedback $Car/Price message 'Price is required';
  else
    if $Car/Price <= 0 then
      set $IsValid = false;
      validation feedback $Car/Price message 'Price must be greater than 0';
    end if;
  end if;

  -- Validate enumeration (required)
  if $Car/CarType = empty then
    set $IsValid = false;
    validation feedback $Car/CarType message 'Car type is required';
  end if;

  return $IsValid;
end;
/
```

### Action Microflow (ACT_Car_NewEdit)

```mdl
/**
 * Handles the Save action for Car NewEdit page
 *
 * Validates the Car, commits it if valid, and closes the page.
 *
 * @param $Car The Car entity to save
 * @returns Boolean indicating success
 */
create microflow MdlTemplates.ACT_Car_NewEdit (
  $Car: MdlTemplates.Car
)
returns boolean as $IsValid
folder 'OverviewPages'
begin
  -- Call validation microflow
  $IsValid = call microflow MdlTemplates.VAL_Car_NewEdit($param = $Car);

  -- Only save if validation passed
  if $IsValid then
    commit $Car;
    close page;
  end if;

  return $IsValid;
end;
/
```

## Validation Patterns

### Simple Required Field Validation

```mdl
if trim($entity/TextField) = '' then
  set $IsValid = false;
  validation feedback $entity/TextField message 'This field is required';
end if;
```

### Numeric Range Validation

```mdl
if $entity/Amount != empty then
  if $entity/Amount < 0 or $entity/Amount > 1000 then
    set $IsValid = false;
    validation feedback $entity/Amount message 'Amount must be between 0 and 1000';
  end if;
end if;
```

### Enumeration Required Validation

```mdl
if $entity/status = empty then
  set $IsValid = false;
  validation feedback $entity/status message 'Status is required';
end if;
```

### Enumeration Value Comparison

**IMPORTANT**: When comparing enumeration values, use the fully qualified enumeration value, NOT a string literal.

```mdl
-- CORRECT: Use fully qualified enumeration value
if $task/TaskStatus = Module.TaskStatus.Completed then
  -- Task is completed
end if;

if $task/TaskStatus != Module.TaskStatus.Cancelled then
  -- Task is not cancelled
end if;

-- WRONG: Do NOT use string literals for enumeration comparison
-- IF $Task/TaskStatus = 'Completed' THEN  -- This is incorrect!
```

### Conditional Validation Based on Enumeration

```mdl
-- Validate CompletedDate only when status is Completed
if $task/TaskStatus = Module.TaskStatus.Completed then
  if $task/CompletedDate = empty then
    set $IsValid = false;
    validation feedback $task/CompletedDate message 'Completed date is required';
  end if;
end if;

-- Validate DueDate for active (non-completed, non-cancelled) tasks
if $task/TaskStatus != Module.TaskStatus.Completed and $task/TaskStatus != Module.TaskStatus.Cancelled then
  if $task/DueDate = empty then
    set $IsValid = false;
    validation feedback $task/DueDate message 'Due date is required for active tasks';
  end if;
end if;
```

### Date Validation

```mdl
if $entity/StartDate != empty and $entity/EndDate != empty then
  if $entity/EndDate < $entity/StartDate then
    set $IsValid = false;
    validation feedback $entity/EndDate message 'End date must be after start date';
  end if;
end if;
```

### Dynamic Message with Template Arguments

```mdl
-- Build validation message with dynamic content
declare $ValidationMessage string = '';
if $entity/value < $entity/MinValue then
  set $ValidationMessage = 'Value must be at least ' + toString($entity/MinValue);
end if;
if $entity/value > $entity/MaxValue then
  set $ValidationMessage = if trim($ValidationMessage) = ''
    then 'Value must be at most ' + toString($entity/MaxValue)
    else $ValidationMessage + '. Value must be at most ' + toString($entity/MaxValue);
end if;

if trim($ValidationMessage) != '' then
  set $IsValid = false;
  validation feedback $entity/value message '{1}' objects [$ValidationMessage];
end if;
```

### Association Validation

```mdl
-- Validate that an association is set
if $Order/Order_Customer = empty then
  set $IsValid = false;
  validation feedback $Order/Module.Order_Customer message 'Customer is required';
end if;
```

## Implementation Checklist

When implementing validation microflows:

1. **Initialize the validation flag**: Always start with `declare $IsValid boolean = true;`

2. **Declare all variables before using SET**: You must use `declare` before `set` for primitive variables. Parameters are automatically available but local variables require declaration.

3. **Validate all required fields**: Check each attribute that needs validation

4. **Set flag to false on error**: `set $IsValid = false;` before showing feedback

5. **Show clear error messages**: Use `validation feedback` with descriptive messages

6. **Return the validation flag**: End with `return $IsValid;`

7. **Handle nullable fields**: Check for `empty` before validating nullable fields

8. **Use appropriate validation order**: Validate presence before other constraints

**Important**: The script executor validates that all variables used with `set` are declared. If you use `set $Var = ...` without a prior `declare $Var type = ...`, you will receive an error like:
```
variable '$Var' is not declared. use declare $Var: <type> before using set
```

## Files Modified

This feature is implemented in:
- `mdl/grammar/MDL.g4` - ANTLR4 grammar with VALIDATION FEEDBACK tokens
- `mdl/ast/ast_microflow.go` - AST type definitions (MfValidationFeedbackStmt)
- `mdl/visitor/visitor_microflow_statements.go` - ANTLR listener to build AST
- `mdl/executor/cmd_microflows_builder.go` - Flow builder with variable validation
- `mdl/executor/cmd_microflows_show.go` - DESCRIBE formatter for MDL output
- `sdk/mpr/writer_microflow.go` - BSON serialization for ValidationFeedbackAction
- `sdk/microflows/microflows_actions.go` - ValidationFeedbackAction struct
