PracticeVideosBlogFlashcards

10.2 Form Validations, Error Handling & Dynamic Display

Key Takeaways

  • Form validations in Appian SAIL are declarative: the validations parameter expects null or an empty list {} to pass, or a text string (or list of strings) to trigger an error banner and block submission.

  • Validations exist at three distinct hierarchical scopes: Component-level (formatting/data constraints), Section-level (multi-field logical dependencies), and Form-level (global aggregate constraints).

  • The validate: true parameter on action buttons enforces validation before completing a task; secondary buttons (such as 'Cancel' or 'Save Draft') must explicitly configure validate: false to prevent blocking submission on invalid or empty fields.

  • showWhen conditionally includes or omits components from the evaluated interface tree; omitting a component from display does NOT clear its underlying variable value in memory.

  • The critical exam distinction between readOnly and disabled: readOnly renders data cleanly as static accessible display text without input borders, whereas disabled renders an inactive, greyed-out interactive input control.

Last updated: October 2026

Form Validations, Error Handling & Dynamic Display

Quick Summary: In Appian SAIL, form validation and dynamic visibility are managed declaratively through standardized component parameters. The validations parameter evaluates at component, section, and form levels, halting workflow submission when text error messages are produced. Developers govern task completion using the validate parameter on buttons, control interface rendering conditionally using showWhen, and precisely differentiate between clean display data (readOnly) and temporarily inactive form controls (disabled).


The Declarative Validation Engine in Appian SAIL

In traditional web frameworks, form validation often requires coordinating complex client-side JavaScript regex listeners with asynchronous backend validation endpoints. Appian SAIL abstracts this complexity through a declarative, server-evaluated validation engine.

Supported input components and appropriate layouts provide a validations parameter. The validation contract is simple and universal:

+-----------------------------------------------------------------------------+
|                   SAIL VALIDATION EVALUATION CONTRACT                       |
+-----------------------------------------------------------------------------+
|  Evaluated Expression Result     | System Validation Behavior               |
|  --------------------------------+------------------------------------------|
|  null or {} (Empty Array)        | PASS: Validation succeeds.               |
|                                  | No error displayed; submission permitted.|
|  --------------------------------+------------------------------------------|
|  "Error message string"          | FAIL: Validation fails.                  |
|  or {"Error 1", "Error 2"}       | Displays red error text beneath field.   |
|                                  | Blocks form submission if validate: true |
+-----------------------------------------------------------------------------+

Built-in Validation Parameters

In addition to the custom validations expression parameter, SAIL components provide built-in validation shorthand:

  • required: true: Automatically marks the field with a red required asterisk (*) and validates required input according to the component contract; trim text explicitly if whitespace-only values must be rejected. If empty upon submission, it generates a standard error message.
  • requiredMessage (Text): Customizes the default required error message (e.g., "Please provide your legal business name before proceeding.").
  • Date boundaries: Use custom validations to compare entered dates against the business limits. Do not invent minDate or maxDate parameters for date components.

Validation Scopes: Component, Section & Form-Level Validations

Appian categorizes validations into three distinct architectural scopes based on where the error message should appear and what data dependencies are involved.

+-----------------------------------------------------------------------------+
|                        HIERARCHICAL VALIDATION SCOPES                       |
+-----------------------------------------------------------------------------+
|                                                                             |
|  1. a!formLayout(validations: ...)                                          |
|     [Global Form Banner: "Total allocation percentages must equal 100%"]    |
|     │                                                                       |
|     ├── 2. a!sectionLayout(validations: ...)                                |
|     │      [Section Banner: "End Date must occur after Start Date"]         |
|     │      │                                                                |
|     │      └── 3. a!textField(validations: ...)                             |
|     │             [Inline Field Error: "Enter a valid corporate email"]     |
+-----------------------------------------------------------------------------+

1. Component-Level Validations

Component validations are attached directly to atomic input fields (a!textField, a!integerField, a!dropdownField). They evaluate constraints specific to that single piece of data.

  • Error Placement: Renders directly beneath the input field with a red border around the input box.
  • Common Use Cases: Regex pattern matching (email formatting, phone numbers, tax IDs), range boundaries (age >= 18), or character length restrictions.
a!textField(
  label: "Corporate Email Address",
  value: ri!employee.email,
  saveInto: ri!employee.email,
  required: true,
  validations: if(
    a!isNullOrEmpty(ri!employee.email),
    null,
    if(
      like(ri!employee.email, "*@acme.com"),
      null,
      "Email address must belong to the corporate domain (@acme.com)."
    )
  )
)

2. Section-Level Validations

Attached to a!sectionLayout(validations: ...). Used when a validation rule depends on relationships between multiple fields grouped inside that section.

  • Error Placement: Renders as a prominent callout message at the bottom or top of the section container.
  • Common Use Cases: Cross-field comparisons where attributing the error to a single field is ambiguous (e.g., ensuring startDate precedes endDate, or verifying that at least one of "Mobile Phone" or "Home Phone" is provided).
a!sectionLayout(
  label: "Contract Performance Period",
  contents: {
    a!dateField(label: "Start Date", value: ri!startDate, saveInto: ri!startDate),
    a!dateField(label: "End Date", value: ri!endDate, saveInto: ri!endDate)
  },
  validations: if(
    and(a!isNotNullOrEmpty(ri!startDate), a!isNotNullOrEmpty(ri!endDate)),
    if(ri!endDate < ri!startDate, "The contract End Date cannot be earlier than the Start Date.", null),
    null
  )
)

3. Form-Level Validations

Attached to the root a!formLayout(validations: ...). Used for aggregate calculations or global workflow conditions spanning multiple disparate sections.

  • Error Placement: Displays at the top of the form layout directly beneath the form title.
  • Common Use Cases: Verifying that a budget distribution table totals exactly 100%, or confirming that at least one line item has been entered across multiple tabs.
AttributeComponent ValidationSection ValidationForm-Level Validation
Componenta!textField(), a!dropdownField(), etc.a!sectionLayout()a!formLayout()
Visual PositionImmediately below the specific fieldBottom/top of the section boxTop banner of the entire form
Target ScopeSingle field data integrityMulti-field cross-validationGlobal form-wide integrity
User NoticeabilityHigh context for specific field typingClear context for grouped logicHigh-level summary of blocking issue

Validation Triggers & Submission Mechanics (validate: true vs. false)

Understanding when validations evaluate is a cornerstone of Appian interface design and a critical topic on the ACD101 exam:

  1. Real-Time Evaluation (On-Change): As a user interacts with a field (typing text, selecting a dropdown value), that component's individual validations expression evaluates immediately. If invalid, the error message appears in real time.
  2. Submit-Time Evaluation (On-Submit): When the user clicks an action button configured with submit: true, the engine triggers a comprehensive validation sweep across all components, sections, and form-level validations on the screen.

The Role of validate: true vs. validate: false on Buttons

The validate parameter on a!buttonWidget() dictates whether the button triggers this comprehensive validation sweep:

a!buttonLayout(
  primaryButtons: {
    a!buttonWidget(
      label: "Submit Application",
      value: "SUBMIT",
      saveInto: ri!buttonAction,
      submit: true,
      style: "SOLID",
      validate: true  /* Enforces all validations; blocks if errors exist */
    )
  },
  secondaryButtons: {
    a!buttonWidget(
      label: "Cancel Request",
      value: "CANCEL",
      saveInto: ri!buttonAction,
      submit: true,
      style: "SOLID", color: "NEGATIVE",
      validate: false  /* CRITICAL: Allows immediate exit without validating */
    ),
    a!buttonWidget(
      label: "Save Draft",
      value: "SAVE_DRAFT",
      saveInto: ri!buttonAction,
      submit: true,
      validate: false  /* Allows saving incomplete forms */
    )
  }
)
                     Button Submission Flowchart
                     ===========================

                   User clicks an a!buttonWidget()
                                 │
                                 ▼
                       Is submit == true?
                       ├──► NO  ──► Execute saveInto only; stay on screen
                       │
                       └──► YES
                             │
                             ▼
                     Is validate == true?
                     ├──► NO  ──► Complete User Input Task immediately
                     │            (No validation sweep; exit cleanly)
                     │
                     └──► YES
                           │
                           ▼
                   Execute full interface validation sweep
                   (Component, Section, and Form validations)
                           │
           ┌───────────────┴───────────────┐
           ▼                               ▼
   Any errors found?               All validations pass?
   ├──► YES                        └──► YES
   │    - Highlight fields in red       - Execute saveInto
   │    - Scroll to first error         - Complete task
   │    - BLOCK task completion         - Advance process token

Partial Validation with validationGroup

In complex multi-step forms or tabbed interfaces, developers often want to validate only a subset of inputs before progressing to the next step. By tagging specific input components and the corresponding "Next" button with matching validationGroup text strings (e.g., validationGroup: "STEP_1"), Appian validates only the components belonging to that group, leaving subsequent steps unvalidated.


Conditional Display Logic with showWhen

Dynamic interfaces adapt their layout to user input—revealing additional questions, showing supplementary sections, or hiding irrelevant controls. In Appian SAIL, conditional visibility is controlled universally via the showWhen parameter.

Supported components and layouts provide showWhen (accepting a boolean expression that evaluates to true or false).

a!radioButtonField(
  label: "Do you have foreign financial assets?",
  choiceLabels: {"Yes", "No"},
  choiceValues: {true, false},
  value: local!hasForeignAssets,
  saveInto: {
    local!hasForeignAssets,
    /* Clear child data if user switches answer back to No */
    if(save!value = false, {a!save(ri!taxFiling.foreignAssetCountry, null), a!save(ri!taxFiling.foreignAssetValue, null)}, {})
  }
),
a!sectionLayout(
  label: "Foreign Asset Disclosures",
  showWhen: local!hasForeignAssets = true,
  contents: {
    a!textField(
      label: "Jurisdiction / Country",
      value: ri!taxFiling.foreignAssetCountry,
      saveInto: ri!taxFiling.foreignAssetCountry,
      required: true
    ),
    a!floatingPointField(
      label: "Aggregate Value ($)",
      value: ri!taxFiling.foreignAssetValue,
      saveInto: ri!taxFiling.foreignAssetValue,
      required: true
    )
  }
)

Architectural Evaluation of showWhen

  1. Server-Side Elimination: When showWhen evaluates to false, the component is completely omitted from the server's serialized UI JSON payload. It does not exist in the client DOM (unlike CSS display: none).
  2. Validation Suppression: Components hidden via showWhen: false do not fire validations. If a hidden text field has required: true, but its parent section has showWhen: false, form submission is not blocked.
  3. Data Retention Caveat: Hiding a component does not reset or clear the underlying variable in memory! If a user types text into a field and then toggles a radio button that hides that field, the entered data still resides in ri! or local!. Developers should explicitly clear child variables in saveInto if business logic requires discarded answers to be null.

Component Interaction States: readOnly vs. disabled

A frequent source of confusion—and a heavily tested concept on the ACD101 exam—is the precise distinction between setting readOnly: true versus disabled: true on SAIL input components.

DimensionreadOnly: truedisabled: true
Visual PresentationRenders cleanly as static text; removes all input boxes, borders, and dropdown arrowsRenders the standard input widget outline, but greyed-out and muted
Semantic IntentCommunicates that this information is informational or finalized data to be readCommunicates that this control exists but is currently unavailable or inactive
Tab NavigationTypically bypassed in tab order; screen readers treat as static contentIncluded in DOM but disabled; keyboard users cannot interact with or focus it
Form Theme IntegrationBlends seamlessly into review screens, summaries, and dashboardsLooks like an interactive form with deactivated switches/fields
Primary Use CasesRead-only summary views, manager approval reviews, confirmation screensConditional inputs waiting for a prerequisite selection (e.g., State disabled until Country selected)
VISUAL COMPARISON:

[readOnly: true]                              [disabled: true]
Customer Name                                 Customer Name
Acme Corporation                              +-------------------------------+
(Clean text, no box; looks like prose)        | Acme Corporation              |
                                              +-------------------------------+
                                              (Grey background, bordered box;
                                               looks like an inactive input)

Realistic Scenario: Multi-Step Wizard Form with Conditional Sections

A commercial loan origination platform utilizes a multi-step intake wizard:

  1. Wizard State: Controlled by local!currentStep: 1.
  2. Step Tracker: An a!milestoneField() visually indicates progress across Step 1 (Borrower Info), Step 2 (Loan Request), and Step 3 (Confirmation).
  3. Conditional Sections:
    • Section 1 (showWhen: local!currentStep = 1) collects applicant details. Its fields belong to validationGroup: "STEP_1".
    • Section 2 (showWhen: local!currentStep = 2) collects requested loan amount and collateral details. If "Collateral Type" is "Real Estate", a nested sub-section displays deed inputs (showWhen: ri!loan.collateralType = "REAL_ESTATE").
    • Section 3 (showWhen: local!currentStep = 3) renders all previously entered data using readOnly: true for executive sign-off.
  4. Action Buttons:
    • "Next Step" button: advances step counter (saveInto: a!save(local!currentStep, local!currentStep + 1)), sets validationGroup: "STEP_1", and sets validate: true.
    • "Previous Step" button: decrements step counter with validate: false.
    • "Cancel Application" button: sets validate: false and submit: true, allowing the user to abort immediately.
    • "Final Submit" button (on Step 3): sets submit: true and validate: true to trigger the workflow process.

Exam Traps & Validation Guidelines

Warning

Common Exam Trap 1: The 'Frozen Cancel Button' Trap. A developer creates a User Input Task with required fields. When testing, clicking "Cancel" fails to close the task and instead paints the form in red error messages. Cause: the developer forgot to set validate: false on the Cancel button. Because validate defaults to true when submit is true, clicking Cancel forces a full validation sweep that blocks submission.

Warning

Common Exam Trap 2: Returning Booleans in validations. The validations parameter expects a text string error message or null. Writing validations: ri!age >= 18 is an evaluation error. The correct expression is validations: if(ri!age < 18, "Applicant must be at least 18 years old.", null).

Tip

Dynamic Form Best Practice: Whenever hiding a dependent section using showWhen, decide whether to retain or reset the underlying dependent data inside the parent component's saveInto. Otherwise, obsolete or conflicting data will silently persist into the database.

Source checked 2026-10-18: Appian button validation behavior.

Test Your Knowledge

A user reports that when clicking the "Cancel Request" button on a User Input Task, the form refuses to close and instead highlights five required fields in red with error messages. What configuration change must the developer make to the Cancel button?

A

Set submit: false and style: "SOLID", color: "NEGATIVE" on the Cancel button.

B

Set showWhen: false on the required fields when the button is pressed.

C

Set required: false on all inputs across the entire form layout.

D

Set validate: false on the Cancel button's a!buttonWidget() configuration.

Test Your Knowledge

What is the primary functional and visual distinction between setting readOnly: true versus disabled: true on an a!textField() in Appian SAIL?

A

readOnly: true presents the value cleanly as static text without input borders, whereas disabled: true displays a greyed-out interactive input box that cannot be edited or focused.

B

readOnly: true wipes the underlying variable value to null, whereas disabled: true retains the value in memory.

C

readOnly: true can only be applied to dropdowns, whereas disabled: true applies exclusively to text fields.

D

readOnly: true prevents users from seeing the component, whereas disabled: true keeps the component fully visible.

Test Your Knowledge

An interface contains a section layout that should only be visible when an applicant selects "Yes" for the "Do you have prior military service?" radio button. How should this conditional visibility be implemented?

A

Set disabled: ri!hasPriorMilitary <> "Yes" on the section layout.

B

Configure showWhen: ri!hasPriorMilitary = "Yes" on the a!sectionLayout().

C

Wrap the section inside a process model XOR gateway condition.

D

Set validations: if(ri!hasPriorMilitary = "Yes", null, "Hide Section") on the section layout.

Sections you finish are checked off in the contents.