Template types
Caseflow templates come in three types:| Type | Purpose |
|---|---|
| Create | Rendering for new objects |
| Update | Rendering for existing objects |
| Preview Pane | Compact, read-oriented view used in the search preview panel |
Template selection
When no explicittemplateName is supplied, selection uses class and template type with access-aware resolution:
- Group-based match first — user group assignment is evaluated, and the highest-precedence matching template is selected
- Default fallback — if no group match exists, the default template is used
Template syntax
Variable resolution
Use{"{{...}}"} for render-time template variables:
Conditionals
- Comparisons:
==,!=,>,<,>=,<= - Logic:
&&,||,! - Grouping with parentheses
Loops
Components and HTML
Templates can mix regular HTML tags with registered custom components (capitalized names). Unknown components render as explicit error placeholders.Property parsing and type coercion
Component props are parsed from strings and coerced where possible:- JSON objects and arrays are auto-parsed when valid
"true"/"false"are converted to booleans- Numeric literals are converted to numbers
Scope model
Template scope contains two namespaces:| Namespace | Keyed by |
|---|---|
ids | Attribute IDs |
names | Attribute names and known aliases |
- Regular object attributes
- Stock attributes (
stock.*) - Object metadata (
ObjectId,ClassName) - User context (
user.id,user.username, etc.) - Alias objects registered via
RelatedObject
Render-time vs runtime variables
This is an important distinction:| Form | Resolution moment | Typical sources |
|---|---|---|
{"{{...}}"} | Template rendering | Object attributes, stock attributes, aliases, user info |
${"${...}"} | Action/script execution | Change context, selected objects, row context, script result |
- Use
{"{{...}}"}for static template composition and default values - Use
${"${...}"}for event-driven logic and action conditions
Runtime variable families
| Context | Variables |
|---|---|
EditableField onChanged | ${newValue}, ${previousValue} |
RelationPicker onChanged | ${newValue}, ${previousValue}, ${selectedObject...} |
ObjectSearch row document config | ${row.stock.objectid}, ${row.AttributeName} |
| Save hooks | ${changedFields}, ${oldValues.X}, ${newValues.X} |
| Script actions | ${scriptResult}, ${scriptResult.path}, ${scriptError} |
| Date/time | ${today}, ${now} |
| Create actions | ${createdObjectId}, ${objectKey} |
Mixed render-time and runtime example
{"{{stock.objectid}}"} is resolved when the template renders, while ${previousValue} and ${newValue} are resolved when the action executes.
Conditional expressions
Actions can be guarded with awhen clause:
Comparison operators
| Operator | Description |
|---|---|
== | Equal |
!= | Not equal |
gt | Greater than |
lt | Less than |
gte | Greater than or equal |
lte | Less than or equal |
String operators
| Operator | Description |
|---|---|
contains | String contains |
startsWith | String starts with |
endsWith | String ends with |
Unary operators
| Operator | Description |
|---|---|
isEmpty | Value is empty |
isNotEmpty | Value is not empty |
isTrue | Value is truthy |
isFalse | Value is falsy |
Logical operators
Combine conditions withand, or, not, or !.
Examples
Workflow transition rule:Nullish coalescing
Use?? in runtime expressions to guard optional relation data:
Action design guidance
Recommended:- Prefer pipe-delimited action chains for readability:
action1 | action2 | action3 - Keep each action idempotent where possible
- Use explicit
queryKeyvalues in all search components that need external refresh - Use
throwErrorinonBeforeSavefor business-rule enforcement
- Long opaque action chains with no conditional guards
- Writing non-persisted temporary values to normal attributes
- Mixing row-level
${row.*}expressions outside row-driven contexts
