Data-binding Syntax (APL for Audio)
You use data-binding syntax to write expressions that Alexa evaluates when rendering your document. You use data-binding expressions to bind component properties to your data source, and to write conditional logic to include and exclude components depending on criteria.
About data binding expressions
You use data binding expressions inside JSON strings. A data binding expression has the form "${expression}
".
You can use any number of expressions inside a string, for example: "${2}+${2} = ${2+2}"
.
Alexa evaluates expressions within the current data-binding context. The data-binding context is a global dictionary that supports booleans, numbers, strings, arrays, objects, and null.
Supported value types
Identifier
An identifier is a name used to identify a data-binding variable. Identifiers must follow the C identifier naming convention: [a-zA-Z_][a-zA-Z0-9_]*
. That is, the identifier must start with an upper or lower-case ASCII letter or underscore and can be followed by zero or more ASCII letters, numbers, or the underscore:
${data}
${_myWord23}
${__AnUgly26_letter__examplE}
String literals
Define strings with either single or double quotes. The starting and ending quote must match. Quotes, carriage returns, and line-feeds can be escaped:
${"Double-quoted string"}
${'Single-quoted string'}
${"Inner quote: \" or '"}
Expressions can be nested inside of a string:
${"Two plus two is ${2+2}"}
Numbers
Positive, negative, and floating-point numbers are supported. Scientific notation is not supported. All numbers are doubles.
Booleans
Boolean values of true and false are supported:
${true}
${false}
Time
Time data types are supported, with a default unit of milliseconds. The only supported units are milliseconds and seconds. Use a suffix of "s" to indicate a unit of "seconds":
${1000}
${1.7s}
null
The null constant is supported:
${null}
Truthy and coercion
Data-binding expressions use different types. These types can be converted into other types. The following table summarizes these type conversions:
Object Type | Example | As Boolean | As Number | As String |
---|---|---|---|---|
Null |
|
|
0 |
"" |
Boolean |
|
|
1 |
"true" |
|
|
0 |
"false" | |
Number |
|
|
23 |
"23" |
|
|
0 |
"0" | |
String |
" |
|
0 |
"My dog" |
"" |
|
0 |
"" | |
" |
|
-2.3 |
"-2.3" | |
" |
|
0 |
"red" | |
Array |
|
|
0 |
"" |
Map |
|
|
0 |
"" |
Time |
|
|
1000 |
1000 |
|
|
0 |
"0" | |
|
|
1700 |
"1.7s" | |
|
|
0 |
"" | |
|
|
0 |
"0s" | |
Anything else |
… |
|
0 |
"" |
Boolean coercion
A truthy value is a value that is considered true when evaluated in a boolean context. All values are truthy except for false
, 0, "", and null
.
Number coercion
The boolean "true" value converts to the number 1. Everything else converts to 0.
String coercion
Internal types convert to strings according to the rules in the following table:
Object | Example | Result | Description |
---|---|---|---|
Null | null | '' |
The null value is not rendered. |
Boolean | true false | 'true' 'false' |
Boolean true & false are rendered as strings. |
Number | -23 | '-23' |
Integers have no decimal places. |
1/3 | '0.333333' |
Non-integers have decimal places. | |
String | "My "dog" " | 'My "dog" ' |
String values |
Array | […] | '' |
Arrays are not rendered |
Map | {…} | '' |
Maps are not rendered |
Anything else | ${Math.min} |
'' |
Math functions are not rendered. |
The specific format of non-integer numbers is not defined, but should follow the C++ standard for sprintf(buf, "%f", value)
. This format might change based on the locale.
Operators
Arithmetic operators
The standard arithmetic operations for addition, subtraction, multiplication, division, and remainder are supported:
${1+2} // 3
${1-2} // -1
${1*2} // 2
${1/2} // 0.5
${1%2} // 1.
Addition and subtraction work for pairs of numbers.
The addition operator also acts as a string-concatenation operator if either the left or right operand is a string:
${27+""} // '27'
${1+" dog"} // '1 dog'
${"have "+3} // 'have 3'
Multiplication, division, and the remainder operator work for pairs of numbers.
The remainder operator behaves as in JavaScript:
${10 % 3} // 1
${-1 % 2} // -1
${3 % -6} // 3
${6.5 % 2} // 0.5
Logical operators
The standard logical AND/OR/NOT operators are supported:
${true && false} // false
${true || false} // true
${!true} // false
The &&
operator returns the first operand when the operand is not truthy and the second otherwise. The ||
operator returns the first operand if it is truthy and the second otherwise:
${7 && 2} // 2
${null && 3} // null
${7 || 2} // 7
${0 || -16} // -16
Comparison operators
Comparison operators return boolean values:
${1 < 2}
${75 <= 100}
${3 > -1}
${4 >= 4}
${myNullValue == null}
${(2>1) == true}
${1 != 2}
The comparison operators don't apply to arrays and objects.
Null-coalescing operator
The ??
operator is the null-coalescing operator. It returns the left-hand operand if the operand is not null; otherwise it returns the right-hand operand. You can chain the null-coalescing operator:
${person.name ?? person.surname ?? 'Hey, you!'}
The null-coalescing operator returns the left-hand operand when it is anything but null:
${1==2 ?? 'Dog'} // returns false
${1==2 || 'Dog'} // returns 'Dog'
Ternary operator
The ternary operator (${a ? b : c}
) evaluates the left-hand operand. If it evaluates to true or a truthy value, the middle operand is returned. Otherwise the right-hand operand is returned:
${person.rank > 8 ? 'General' : 'Private'}
Array and object access
Array
Array access uses the []
operator, where the operand should be an integer. Arrays also support the .length
operator to return the length of the array. Accessing an element outside of the array bounds returns null:
${myArray[4]} // 5th element in the array (0-indexed)
${myArray.length} // Length of the array
${myArray[-1])} // Last element in the array
${myArray[myArray.length]} // Returns null (out of bounds)
Passing a negative index counts backwards through the array:
${a[-1] == a[a.length - 1]} // True
Object
Objects support the .
operator and the []
array access operator with string values:
${myObject.name} // The 'name' property of myObject
${myObject['name']} // The 'name' property of myObject
An undefined property returns null. Calling the .
or []
operator on null returns null:
${myNullObject.address.zipcode} // Returns null
The right-side operand of the dot operator must be a valid identifier.
Function calls
Functions
Data-binding supports a limited number of built-in functions. Functions use the form:
functionName( arg1, arg2, … )
Functions don't require arguments. A function returns a single value.
Built-in functions
Property | Description | Example |
---|---|---|
Math.abs(x) |
Return the absolute value of x | ${Math.abs(-2.3)} == 2.3 |
Math.acos(x) |
The arccosine of x | ${Math.acos(1)} == 0 |
Math.asin(x) |
The arcsine of x | ${Math.asin(0)} == 0 |
Math.atan(x) |
The arctangent of x | ${Math.atan(1)} == 0.7853981633974483 |
Math.ceil(x) |
Return the smallest integer greater than or equal to x. | ${Math.ceil(2.3)} == 3 |
Math.clamp(x,y,z) |
Return x if y<x, z if y>z and otherwise y. | ${Math.clamp(1, 22.3,10)} == 10 |
Math.cos(x) |
The cosine of x | ${Math.cos(0)} == 1 |
Math.floor(x) |
Return the largest integer less than or equal to x. | ${Math.floor(2.3)} = 2 |
Math.max(x1,x2,…) |
Return the largest argument | ${Math.max(2,3)} == 3 |
Math.min(x1,x2,…) |
Return the smallest argument | ${Math.min(2,3)} == 2 |
Math.PI |
The value of π | 3.141592653589793 |
Math.random() |
A random number between 0 and 1 | ${Math.random()} == 0.7113654073137101 (but not every time!) |
Math.round(x) |
Return the nearest integer to x | ${Math.round(2.3)} == 2 |
Math.sign(x) |
The sign of x: -1, 0, or +1 | ${Math.sign(-43.1) == -1 |
Math.sin(x) |
The sine of x | ${Math.sin(Math.PI/6)} == 0.5 |
Math.sqrt(x) |
The square root of x | ${Math.sqrt(9)} == 3 |
Math.tan(x) |
The tangent of x | ${Math.tan(Math.PI/4)} == 0.5 |
String.slice(x,y[,z]) |
Return the subset of x starting at index y and extending to but not including index z. If z is omitted, the remainder of the string is returned. If y is a negative number, select from the end of the string. | ${String.slice("berry", 2, 4)} == "rr" ${String.slice("berry", -2)} == "ry" |
String.toLowerCase(x) |
Return a lower-case version of x | ${String.toLowerCase("bEn")} == "ben" |
String.toUpperCase(x) |
Return an upper-case version of x | ${String.toUpperCase("bEn")} == "BEN" |
Data-binding string conversion
Because APL is serialized in JSON, all data-bound expressions are defined inside of a JSON string:
{
"MY_EXPRESSION": "${....}"
}
If there are no spaces between the quotation marks and the data-binding expression, the result of the expression is the result of the data-binding evaluation. For example:
"${true}" -> Boolean true
"${2+4}" -> Number 6
"${0 <= 1 && 'three'}" -> String 'three'
When extra spaces are in the string outside of the data-binding expression or when two data-binding expressions are juxtaposed, the result is a string concatenation:
" ${true}" -> String ' true'
"${2+4} " -> String '6 '
"${2+1}${1+2}" -> String '33'
Last updated: Nov 28, 2023