# Form Validation

Validate forms using ColdBox's [cbValidation](https://coldbox-validation.ortusbooks.com/) engine. CBWIRE automatically validates components on each request when constraints are defined, and provides helper methods for displaying validation errors.

## Installation

Install cbValidation via CommandBox:

```bash
box install cbvalidation
```

## Basic Usage

Create a user registration form with validation:

{% tabs %}
{% tab title="BoxLang" %}

```javascript
// wires/UserRegistration.bx
class extends="cbwire.models.Component" {
    data = {
        "name": "",
        "email": "",
        "password": "",
        "confirmPassword": ""
    };
    
    constraints = {
        "name": {
            "required": true,
            "requiredMessage": "Name is required",
            "size": "2..50"
        },
        "email": {
            "required": true,
            "requiredMessage": "Email is required",
            "type": "email"
        },
        "password": {
            "required": true,
            "requiredMessage": "Password is required",
            "size": "8..50"
        },
        "confirmPassword": {
            "required": true,
            "sameAs": "password",
            "sameAsMessage": "Passwords must match"
        }
    };
    
    function register() {
        validateOrFail();
        
        // Save user data
        // redirect("/dashboard");
    }
}
```

{% endtab %}

{% tab title="CFML" %}

```javascript
// wires/UserRegistration.cfc
component extends="cbwire.models.Component" {
    data = {
        "name" = "",
        "email" = "",
        "password" = "",
        "confirmPassword" = ""
    };
    
    constraints = {
        "name" = {
            "required" = true,
            "requiredMessage" = "Name is required",
            "size" = "2..50"
        },
        "email" = {
            "required" = true,
            "requiredMessage" = "Email is required",
            "type" = "email"
        },
        "password" = {
            "required" = true,
            "requiredMessage" = "Password is required",
            "size" = "8..50"
        },
        "confirmPassword" = {
            "required" = true,
            "sameAs" = "password",
            "sameAsMessage" = "Passwords must match"
        }
    };
    
    function register() {
        validateOrFail();
        
        // Save user data
        // redirect("/dashboard");
    }
}
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="BoxLang" %}

```html
<!-- wires/userRegistration.bxm -->
<bx:output>
<div>
    <h1>User Registration</h1>
    
    <bx:if hasErrors()>
        <div class="alert alert-danger">
            <h4>Please fix the following errors:</h4>
            <ul>
                <bx:loop array="#getErrors()#" item="error">
                    <li>#error#</li>
                </bx:loop>
            </ul>
        </div>
    </bx:if>
    
    <form wire:submit.prevent="register">
        <div class="form-group">
            <label for="name">Name:</label>
            <input type="text" 
                   id="name" 
                   wire:model.blur="name" 
                   class="form-control #hasError('name') ? 'is-invalid' : ''#">
            <bx:if hasError("name")>
                <span class="invalid-feedback">#getError("name")#</span>
            </bx:if>
        </div>
        
        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" 
                   id="email" 
                   wire:model.blur="email" 
                   class="form-control #hasError('email') ? 'is-invalid' : ''#">
            <bx:if hasError("email")>
                <span class="invalid-feedback">#getError("email")#</span>
            </bx:if>
        </div>
        
        <div class="form-group">
            <label for="password">Password:</label>
            <input type="password" 
                   id="password" 
                   wire:model.blur="password" 
                   class="form-control #hasError('password') ? 'is-invalid' : ''#">
            <bx:if hasError("password")>
                <span class="invalid-feedback">#getError("password")#</span>
            </bx:if>
        </div>
        
        <div class="form-group">
            <label for="confirmPassword">Confirm Password:</label>
            <input type="password" 
                   id="confirmPassword" 
                   wire:model.blur="confirmPassword" 
                   class="form-control #hasError('confirmPassword') ? 'is-invalid' : ''#">
            <bx:if hasError("confirmPassword")>
                <span class="invalid-feedback">#getError("confirmPassword")#</span>
            </bx:if>
        </div>
        
        <button type="submit" class="btn btn-primary">Register</button>
    </form>
</div>
</bx:output>
```

{% endtab %}

{% tab title="CFML" %}

```html
<!-- wires/userRegistration.cfm -->
<cfoutput>
<div>
    <h1>User Registration</h1>
    
    <cfif hasErrors()>
        <div class="alert alert-danger">
            <h4>Please fix the following errors:</h4>
            <ul>
                <cfloop array="#getErrors()#" item="error">
                    <li>#error#</li>
                </cfloop>
            </ul>
        </div>
    </cfif>
    
    <form wire:submit.prevent="register">
        <div class="form-group">
            <label for="name">Name:</label>
            <input type="text" 
                   id="name" 
                   wire:model.blur="name" 
                   class="form-control #hasError('name') ? 'is-invalid' : ''#">
            <cfif hasError("name")>
                <span class="invalid-feedback">#getError("name")#</span>
            </cfif>
        </div>
        
        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" 
                   id="email" 
                   wire:model.blur="email" 
                   class="form-control #hasError('email') ? 'is-invalid' : ''#">
            <cfif hasError("email")>
                <span class="invalid-feedback">#getError("email")#</span>
            </cfif>
        </div>
        
        <div class="form-group">
            <label for="password">Password:</label>
            <input type="password" 
                   id="password" 
                   wire:model.blur="password" 
                   class="form-control #hasError('password') ? 'is-invalid' : ''#">
            <cfif hasError("password")>
                <span class="invalid-feedback">#getError("password")#</span>
            </cfif>
        </div>
        
        <div class="form-group">
            <label for="confirmPassword">Confirm Password:</label>
            <input type="password" 
                   id="confirmPassword" 
                   wire:model.blur="confirmPassword" 
                   class="form-control #hasError('confirmPassword') ? 'is-invalid' : ''#">
            <cfif hasError("confirmPassword")>
                <span class="invalid-feedback">#getError("confirmPassword")#</span>
            </cfif>
        </div>
        
        <button type="submit" class="btn btn-primary">Register</button>
    </form>
</div>
</cfoutput>
```

{% endtab %}
{% endtabs %}

## Validation Methods

### validateOrFail()

Validates data and silently stops function execution if validation fails (does not throw an exception):

```javascript
function register() {
    validateOrFail(); // Stops execution here if validation fails
    
    // This code only runs if validation passes
    // Save user data
    redirect("/dashboard");
}
```

### validate()

Returns a ValidationResult object for manual error handling:

```javascript
function register() {
    var result = validate();
    
    if (!result.hasErrors()) {
        // Save user data
        redirect("/dashboard");
    } else {
        // Handle errors manually if needed
    }
}
```

## Error Display Methods

### All Errors

Display all validation errors:

```javascript
hasErrors()    // Returns true if any validation errors exist
getErrors()    // Returns array of all error messages
```

### Field-Specific Errors

Display errors for specific fields:

```javascript
hasError("fieldName")    // Returns true if field has errors
getError("fieldName")    // Returns error message for field
```

## Common Constraints

Most frequently used validation constraints:

| Constraint | Description                    | Example                        |
| ---------- | ------------------------------ | ------------------------------ |
| `required` | Field must have a value        | `{"required": true}`           |
| `type`     | Field must be specific type    | `{"type": "email"}`            |
| `size`     | String length or numeric range | `{"size": "8..50"}`            |
| `min/max`  | Minimum/maximum value          | `{"min": 1, "max": 100}`       |
| `sameAs`   | Must match another field       | `{"sameAs": "password"}`       |
| `regex`    | Must match regular expression  | `{"regex": "^[A-Z].*"}`        |
| `inList`   | Value must be in list          | `{"inList": "red,blue,green"}` |

## Advanced Validation

### Custom Constraints

Define validation constraints inline:

```javascript
function processForm() {
    var result = validate(
        target = data,
        constraints = {
            "email": {"required": true, "type": "email"},
            "age": {"required": true, "min": 18}
        }
    );
    
    if (!result.hasErrors()) {
        // Process form
    }
}
```

### Conditional Validation

Use `requiredIf` and `requiredUnless` for conditional validation:

```javascript
constraints = {
    "phone": {
        "requiredIf": {"contactMethod": "phone"},
        "type": "telephone"
    },
    "email": {
        "requiredUnless": {"contactMethod": "phone"},
        "type": "email"
    }
};
```

{% hint style="info" %}
CBWIRE automatically validates components when constraints are defined. Validation runs on each request before actions execute.
{% endhint %}

{% hint style="warning" %}
For complete constraint documentation, see [cbValidation documentation](https://coldbox-validation.ortusbooks.com/).
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://cbwire.ortusbooks.com/features/form-validation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
