Skip to content

Validations

Data Dictionary validations guard the boundary between UI buffers and adapter/database operations by checking or adjusting data before save and find workflows use it.

Related links:

Validation model

cDataDictionary composes validation mixins and owns local record buffers. Validation runs against those Data Dictionary buffers before code continues with save, find, or field-specific workflows.

Request_Validate validates the current Data Dictionary and required parent path. Request_Validate_All collects validation across the DDO structure. Validate_Field validates one field.

Validation functions return True when invalid and False when valid. FieldError hField eErrNr sErrText raises the validation error and records the current validation field for extended error information.

Call validation explicitly when code needs a validation pass before save or before continuing after a field edit.

Running validation

Use Db\cDataDictionary.pkg

Boolean bInvalid

Send Clear of oCustomerDD
Set Field_Option of oCustomerDD (RefTable(oCustomerDD.Name)) DD_Required to True

Get Request_Validate of oCustomerDD to bInvalid
If (bInvalid) Begin
    Procedure_Return
End

Set Field_Changed_Value of oCustomerDD (RefTable(oCustomerDD.Name)) to "Data Access"
Get Validate_Field of oCustomerDD (RefTable(oCustomerDD.Name)) to bInvalid

Explicit validation is useful before save or when code needs to validate a single user-edited field before continuing.

Built-in field options

Option Behavior
DD_Required Attaches required-field validation. Strings and wstrings fail when the trimmed value is empty; numbers fail when zero. Raises DFERR_ENTRY_REQUIRED with Field value required.
DD_FindReq Requires an active related parent record for relation fields or matching foreign-field categories. Raises DFERR_ENTER_VALID_REC_ID with Please enter a valid record ID.
DD_Capslock Adjusts field values written to the Data Dictionary buffer to uppercase. This is value-adjustment behavior, not a validation failure.
Set Field_Option (RefTable(Self.Name)) DD_Required to True
Set Field_Option (RefTable(Self.State)) DD_Capslock to True
Set Foreign_Field_Option DD_KEYFIELD DD_FindReq to True

Validation events

Level Methods Payload Use
DD-level OnValidate_Add, OnValidate_Del, OnValidate_Has tDD_OnValidate Whole-record or cross-field checks.
Field-level OnFieldValidate_Add, OnFieldValidate_Del, OnFieldValidate_Has tDD_OnFieldValidate One field's validation rule.
Foreign-field-level OnForeignFieldValidate_Add, OnForeignFieldValidate_Del, OnForeignFieldValidate_Has tDD_OnForeignFieldValidate Parent/child relation validation such as find-required behavior.
Field-value-change OnFieldValueChange_Add, OnFieldValueChange_Del, OnFieldValueChange_Has tDD_OnFieldValueChange Adjustments such as capslock before a value reaches the DD buffer.

Payload fields:

Payload Fields
tDD_OnValidate hoDD, bInValid
tDD_OnFieldValidate hoDD, hField, bInvalid
tDD_OnForeignFieldValidate hoDD, hoParentDD, hField, bInvalid
tDD_OnFieldValueChange hoDD, hField, vValue

Handler signature:

Procedure HandlerName <PayloadType> ByRef details Boolean ByRef bCancel

For validation failures, set the invalid flag and call FieldError. Set bCancel=True only when a handler intentionally stops later handlers.

Mixin-style validators

Built-in field options are implemented as mixins that register field-option handlers globally and attach or detach event handlers when a field option is set.

Define DD_UsernameRequired for "USERNAME_REQUIRED"

Class cDD_UsernameRequired_mixin is a Mixin
    Procedure Validate_DD_UsernameRequired tDD_OnFieldValidate ByRef details Boolean ByRef bCancel
        String sValue

        Get Field_Current_Value of details.hoDD details.hField to sValue
        If (Trim(sValue) = "") Begin
            Send FieldError of details.hoDD details.hField DFERR_OPERATOR "Username is required"
            Move True to details.bInvalid
        End
    End_Procedure

    Procedure Set_DD_UsernameRequired tDD_OnSetFieldAttribute ByRef details Boolean ByRef bCancel
        If (DD_MetaValueIsTrue(details.vValue)) Begin
            Send OnFieldValidate_Add of details.hoDD details.hField (RefProc(Validate_DD_UsernameRequired)) Self
        End
        Else Begin
            Send OnFieldValidate_Del of details.hoDD details.hField (RefProc(Validate_DD_UsernameRequired)) Self
        End
        Move True to details.bStored
    End_Procedure

    Procedure Get_DD_UsernameRequired tDD_OnGetFieldAttribute ByRef details Boolean ByRef bCancel
        Move (OnFieldValidate_Has(details.hoDD, details.hField, (RefProc(Validate_DD_UsernameRequired)), Self)) to details.vValue
    End_Procedure
End_Class

Send OnSetFieldAttribute_Add of ghoGlobalDDMetaDataHandlers DD_UsernameRequired (RefProc(Set_DD_UsernameRequired)) C_UnresolvedObject
Send OnGetFieldAttribute_Add of ghoGlobalDDMetaDataHandlers DD_UsernameRequired (RefProc(Get_DD_UsernameRequired)) C_UnresolvedObject

Use this style when the behavior belongs in a reusable Data Dictionary subclass or mixin package.

Object-style field validators

cDD_Field_Validator is the shorter object-oriented pattern for reusable field validators.

Contract:

  • Use Db\cDD_Field_Validator.pkg.
  • Define a field option id such as Define DD_EmailAddress for "CUSTOM_EMAILADDRESS".
  • Create an object based on cDD_Field_Validator.
  • Set psOptionId before End_Construct_Object.
  • Override Procedure Validate_DD_Field tDD_OnFieldValidate ByRef details Boolean ByRef bCancel.
  • Read the value with Get Field_Current_Value of details.hoDD details.hField to sValue.
  • On failure, Send FieldError of details.hoDD details.hField DFERR_OPERATOR "..." and Move True to details.bInvalid.
  • Enable per field with Set Field_Option ... DD_EmailAddress to True; disable with False.
Use Db\cDD_Field_Validator.pkg

Define DD_EmailAddress for "CUSTOM_EMAILADDRESS"

Object oEmailValidator is a cDD_Field_Validator
    Set psOptionId to DD_EmailAddress

    Procedure Validate_DD_Field tDD_OnFieldValidate ByRef details Boolean ByRef bCancel
        Integer iAt iDot
        String sValue

        Get Field_Current_Value of details.hoDD details.hField to sValue
        If (Trim(sValue) <> "") Begin
            Move (Pos("@", sValue)) to iAt
            Move (RightPos(".", sValue)) to iDot

            If (not(iAt > 1 and iDot > 0 and iDot > iAt + 1 and iDot < Length(sValue))) Begin
                Send FieldError of details.hoDD details.hField DFERR_OPERATOR "Please enter a valid email address"
                Move True to details.bInvalid
            End
        End
    End_Procedure
End_Object

Class cCustomerDataDictionary is a cDataDictionary
    Procedure Construct_Object
        Forward Send Construct_Object

        Set phEntity to (RefEntity(Customer))
        Set Field_Option (RefTable(Self.EMail_Address)) DD_EmailAddress to True
    End_Procedure
End_Class

The same object can be enabled on matching fields in multiple Data Dictionary classes, so rules such as email format or username policy stay centralized.

Choosing a validator style

Style Best for
Mixin-style Shipping a reusable DD subclass or mixin package, or when the rule must also provide custom option get/set behavior.
Object-style cDD_Field_Validator One reusable field validation rule that should be globally available and enabled by field option across many DDs.

Value-adjustment rules such as capslock should use field-value-change handlers. Validation failures should use validation handlers and FieldError.

API checklist

  • Choose a unique field option id string, e.g. CUSTOM_EMAILADDRESS.
  • Register option handlers globally through cDD_Field_Option, cDD_Field_Validator, or explicit OnSetFieldAttribute_Add / OnGetFieldAttribute_Add calls.
  • Attach/detach event handlers when the option value changes.
  • Use DD_MetaValueIsTrue for option truthiness.
  • Read values from details.hoDD and details.hField, not from a global table buffer.
  • On validation failure, call FieldError and set the payload invalid flag.
  • Verify Field_Option returns the expected state through the matching *_Has API.
  • Keep event handlers reusable and side-effect-light; value transformation belongs in OnFieldValueChange, while rejection belongs in validation events.