State-Based Validation

State-based validation allows you to create validation rules that can fail in multiple ways, each with its own specific error message. This is particularly useful for complex validation scenarios where a single property might fail validation for different reasons depending on its state.

Overview

The StateRule class enables you to define validation logic that evaluates to different states, where only one state is considered valid. Each state can have its own custom error message, making it easy to provide specific feedback to users based on why the validation failed.

Basic Usage

State-based validation is implemented using the satisfiesState() method on the validation rules fluent API. Here's how to use it:

import { resolve } from '@aurelia/kernel';
import { IValidationRules } from '@aurelia/validation';

export class RegistrationForm {
  private validationRules = resolve(IValidationRules);

  public username: string = '';

  public constructor() {
    this.validationRules
      .on(this)
      .ensure('username')
      .satisfiesState(
        'valid',
        (value: string) => {
          if (!value) return 'empty';
          if (value.length < 3) return 'tooShort';
          if (!/^[a-zA-Z0-9_]+$/.test(value)) return 'invalidChars';
          return 'valid';
        },
        {
          empty: 'Username is required.',
          tooShort: 'Username must be at least 3 characters.',
          invalidChars: 'Username can only contain letters, numbers, and underscores.'
        }
      );
  }
}

How It Works

The satisfiesState() method takes three parameters:

  1. validState: The state value that represents a successful validation (e.g., 'valid')

  2. stateFunction: A function that evaluates the value and returns the current state

  3. messages: An object mapping each possible state to its error message

When validation runs:

  • The stateFunction is called with the current value

  • It returns a state (any PropertyKey type: string, number, or symbol)

  • If the returned state matches validState, validation passes

  • If the returned state is different, validation fails with the corresponding message

Async State Validation

The state function can also be asynchronous, allowing you to perform server-side validation or other async operations:

Access to Object Context

The state function receives both the property value and the object being validated, allowing you to create complex validation logic that depends on other properties:

Complete Example

Here's a comprehensive example showing state-based validation in a user registration form:

Important Notes

  • Serialization: StateRule instances cannot be serialized to JSON. If you attempt to serialize a state rule, you'll receive a warning in development mode.

  • Message Keys: The state returned by your function becomes the message key. Ensure all possible states have corresponding messages in the messages object.

  • Valid State: Any state value can be used as the valid state - it doesn't have to be the string 'valid'. You could use numbers, symbols, or any other PropertyKey value.

  • Dynamic Messages: The messages are evaluated at runtime, so you can include interpolation expressions in them just like standard validation rules.

When to Use State-Based Validation

State-based validation is ideal when:

  • A single property can fail validation in multiple distinct ways

  • You want to provide specific, contextual error messages for each failure mode

  • Your validation logic involves complex conditional checks

  • You need to perform async validation with multiple possible outcomes

  • Standard validation rules become unwieldy due to multiple .when() conditions

For simpler scenarios where a property only needs one type of validation, stick to the standard validation rules like .required(), .matches(), etc.

Last updated

Was this helpful?