# APL Data-Binding Syntax (APL 1.4)

*(This is not the most recent version of APL. Use the Other Versions option to see the documentation for the most recent version of APL)*

You use *data-binding syntax* to write expressions that Alexa evaluates when displaying your document. You use data-binding expressions to bind component properties to your data source, and to write conditional logic to hide and show components depending on criteria such as the viewport characteristics.

- About data binding expressions
- Supported value types
- Truthy and Coercion
- Operators
- Array and Object access
- Function calls
- Math functions
- String functions
- Time functions
- Data-binding string conversion

## 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}"`

.

Expressions are evaluated within the current data-binding context. The data-binding context is a global dictionary that supports booleans, numbers, strings, arrays, objects, null, and references to defined resources.

## 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 may be followed by
zero or more ASCII letters, numbers, or the underscore:

```
${data}
${_myWord23}
${__AnUgly26_letter__examplE}
```

### String literals

Strings are defined using either single or double quotes. The starting and ending quote must match. Quotes, carriage returns, and line-feeds may be escaped.

```
${"Double-quoted string"}
${'Single-quoted string'}
${"Inner quote: \" or '"}
```

Expressions may 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 internally stored as doubles:

```
${1}
${-34.75}
${64000000000}
```

### Booleans

Boolean values of `true`

and `false`

are supported.

```
${true}
${false}
```

### null

The `null`

constant is supported.

```
${null}
```

### Resources

Resources defined in the data-binding context use the reserved character "@". For example:

```
${@myBlue}
${@isLandscape ? @myWideValue : @myNarrowValue}
```

APL packages define resources exposed in data-binding.

### Absolute dimensions

A dimensional suffix converts a number into an absolute viewport dimension. The valid dimensional suffixes are "dp", "px", "vh", and "vw":

```
${23 dp} // 23 display-independent pixels
${10 px} // 10 pixels
${50 vw} // 50% of the width of the viewport
${100vh} // 100% of the height of the viewport
```

Dimensional suffixes must be attached to a number, not a more complex expression. For example `${(20*20) dp}`

is not valid, but `${20*20dp}`

is valid.

## Truthy and Coercion

Data-binding expressions involve a number of different types. These types may be converted into other types. The following table gives an example of the different conversions (note that this assumes a viewport width of 512dp and a dpi of 320):

Object | Example | As Boolean | As Number | As String | As Color | As Dimension |
---|---|---|---|---|---|---|

Null | null | false | 0 | "" | transparent | 0dp |

Boolean | true | true | 1 | "true" | transparent | 0dp |

Boolean | false | false | 0 | "false" | transparent | 0dp |

Number | 23 | true | 23 | "23" | #00000017 | 23dp |

Number | 0 | false | 0 | "0" | transparent | 0dp |

String | "My dog" | true | 0 | "My dog" | transparent | 0dp |

String | "" | false | 0 | "" | transparent | 0dp |

String | "-2.3" | true | -2.3 | "-2.3" | transparent | -2.3dp |

String | "red" | true | 0 | "red" | #ff0000ff | 0dp |

String | "50vw" | true | 50 | "50vw" | transparent | 256dp |

Array | [] | true | 0 | "" | transparent | 0dp |

Map | {} | true | 0 | "" | transparent | 0dp |

Color | red | true | 0 | "#ff0000ff" | #ff0000ff | 0dp |

Dimension | 32px | true | 16 | "16dp" | transparent | 16dp |

Dimension | 0vh | false | 0 | "0dp" | transparent | 0dp |

Dimension | 23% | true | 0.23 | "23%" | transparent | 23% |

Dimension | 0% | false | 0 | "0%" | transparent | 0% |

Dimension | auto | true | 0 | "auto" | transparent | auto |

Anything else | ... | true | 0 | "" | transparent | 0dp |

### 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`

, `""`

, a zero
absolute or relative dimension, and `null`

.

### Number coercion

The Boolean "true" value is converted to the number 1. String values
are converted using the C++ `std::stod`

method (note that this is
influenced by the locale). Absolute dimensions convert to the number of
dp in the absolute dimension; relative dimensions convert to the
percentage value (e.g., 32% -> 0.32). Everything else converts to 0.

### String coercion

Internal types are converted to strings using the rules in the following table:

Object | Example | Result | Description |
---|---|---|---|

Null | null | `''` |
The null value is not displayed. |

Boolean | true false | `'true'` `'false'` |
Boolean true & false are displayed 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 displayed. |

Map | {...} | `''` |
Maps are not displayed |

Color | red | `'#ff0000ff'` |
Colors are shown in #rrggbbaa format. |

Dimension | 23 dp | `'20dp'` |
Absolute dimensions are shown with the suffix 'dp' |

Dimension | 20 % | `'20%'` |
Percentage dimensions are shown with the suffix '%' |

Dimension | auto | `'auto'` |
The auto dimension is shown as 'auto' |

Anything else | `${Math.min}` |
`''` |
Math functions are not shown. |

The specific format of non-integer numbers is not defined, but should
follow closely the C++ standard for `sprintf(buf, "%f", value)`

. It may
change based on the locale.

### Color coercion

Color values are stored internally as 32-bit RGBA values. Numeric values will are treated as unsigned 32-bit integers and converted directly. String values are parsed according to the rules in Data Types - Color.

### Absolute dimension coercion

Numeric values are assumed to be measurements in "dp" and are converted to absolute dimensions. String values are parsed according to the rules in Data Types - Dimension. All other values are 0.

### Relative dimension coercion

Numeric values are assumed to be percentages and are converted directly. For example, 0.5 converts to 50%. Strings are parsed according to the rules in Data Types - Dimension. All other values are 0.

## Operators

APL supports different types of operators: arithmetic, logical, comparison, and ternary.

### 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, absolute dimensions, and relative dimensions. When a number is combined with either an absolute or relative dimension, the number is coerced into the appropriate dimension.

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. Multiplication also works if the one of the operands is a dimension (either relative or absolute) and the other is a number; the result is a dimension. Division also works if the first operand is a dimension (either relative or absolute) and the second is a number; the result is a dimension.

The remainder operator behaves as in JavaScript. That is,

```
${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} // true
${true && false} // false
${!true} // false
```

The `&&`

returns the first operand if it 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.

Comparison operators don't perform type coercion.l For example, the expression `${1=='1'}`

returns false. The following table lists the valid comparisons. All other comparisons return false.

Comparison types | <, >, <=, >= | ==, != | Notes |
---|---|---|---|

Number to Number | Valid | Valid | |

Number to Absolute Dimension | Valid | Valid | The number is treated as a display-independent pixel dimension |

Number to Relative Dimension | Valid | Valid | The number is treated as a percentage. For example, 0.4 equals 40%. |

Relative Dimension to Relative Dimension | Valid | Valid | The dimensions are compared as percentages. |

Absolute Dimension to Absolute Dimension | Valid | Valid | The dimensions are converted to display-independent pixels. |

String to String | Valid | Valid | |

Boolean to Boolean | False | Valid | |

Color to Color | False | Valid | |

Null to Null | False | Valid | `${null==null}` is true |

Auto to Auto Dimension | False | Valid | Two auto dimensions are equal (even if the final size is not equal) |

All other combinations | False | False |

The `==`

operator in APL is similar to the `===`

operator in JavaScript.

### Null coalescing

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. The null-coalescing operator may be chained:

```
${person.name ?? person.surname ?? 'Hey, you!'}
```

The null-coalescing operator will return the left-hand operand if it is anything but null:

```
${1==2 ?? 'Dog'} // returns false
${1==2 || 'Dog'} // returns 'Dog'
```

### Ternary Operator

The ternary conditional 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
```

If the property is not defined, `null`

is returned.

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

Data-binding supports a limited number of built-in functions. Functions use the form:

```
functionName( arg1, arg2, … )
```

Functions do not require arguments. A function returns a single value. The following examples show a variety of functional expressions.

```
${Math.floor(1.1)} // 1
${Math.ceil(1.2)} // 2
${Math.round(1.2)} // 1
${Math.min(1,2,3,4)} // 1
${Math.max(1,2,3,4)} // 4
${String.toUpperCase('Hello')} // HELLO
${String.toLowerCase('Hello')} // hello
${String.slice('Hello', 1, -1)} // ell
```

The available functions are grouped by top-level property:

## Math functions

The top-level `Math`

property is a collection of functions and constants for numerical calculations.

Function | Description | Example |
---|---|---|

`Math.abs(x)` |
The absolute value of x | `${Math.abs(-2.3)} == 2.3` |

`Math.acos(x)` |
The arccosine of x | `${Math.acos(1)} == 0` |

`Math.acosh(x)` |
The hyperbolic arccosine of x | `${Math.acosh(1)} == 0` |

`Math.asin(x)` |
The arcsine of x | `${Math.asin(0)} == 0` |

`Math.asinh(x)` |
The hyperbolic arcsine of x | `${Math.asinh(2)} == 1.4436354751788103` |

`Math.atan(x)` |
The arctangent of x | `${Math.atan(1)} == 0.7853981633974483` |

`Math.atanh(x)` |
The hyperbolic arctangent of x | `${Math.atanh(0.5)} == 0.5493061443340548` |

`Math.atan2(y,x)` |
The arc tangent of y/x | `${Math.atan2(1,0)} == 1.5707963267948966` |

`Math.cbrt(x)` |
The cube root of x | `${Math.cbrt(8)} == 2` |

`Math.ceil(x)` |
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.cosh(x)` |
The hyperbolic cosine of x | `${Math.cosh(0)} == 1` |

`Math.exp(x)` |
e raised to the x, where e is Euler's constant. |
`${Math.exp(1)} == 2.718281828459045` |

`Math.exp2(x)` |
2 raised to the x | `${Math.exp2(5)} == 32` |

`Math.expm1(x)` |
e raised to the x minus 1. |
`${Math.expm1(1)} == 1.718281828459045` |

`Math.floor(x)` |
The largest integer less than or equal to x. | `${Math.floor(2.3)} == 2` |

`Math.hypot(x1,x2,…)` |
The square root of the sum of the squares of the arguments | `${Math.hypot(3,4)} == 5` |

`Math.log(x)` |
The natural logarithm of x | `${Math.log(Math.E)} == 1` |

`Math.log1p(x)` |
The natural logarithm of 1+x | `${Math.log1p(1)} == 0.6931471805599453` |

`Math.log10(x)` |
The base-10 logarithm of x | `${Math.log10(100)} == 2` |

`Math.log2(x)` |
The base-2 logarithm of x | `${Math.log2(32)} == 5` |

`Math.max(x1,x2,…)` |
The largest argument | `${Math.max(2,3)} == 3` |

`Math.min(x1,x2,…)` |
The smallest argument | `${Math.min(2,3)} == 2` |

`Math.pow(x,y)` |
Raises x to the y power | `${Math.pow(3,4)} == 81` |

`Math.random()` |
A random number between 0 and 1 | `${Math.random()} == 0.7113654073137101` (the actual random number returned is different) |

`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.sinh(x)` |
The hyperbolic sine of x | `${Math.sinh(1)} == 1.1752011936438014` |

`Math.sqrt(x)` |
The square root of x | `${Math.sqrt(9)} == 3` |

`Math.tan(x)` |
The tangent of x | `${Math.tan(Math.PI/4)} == 1` |

`Math.tanh(x)` |
The hyperbolic tangent of x | `${Math.tanh(10)} == 0.9999999958776927` |

`Math.trunc(x)` |
The integer portion of x | `${Math.trunc(-1.2)} == -1` |

Constant | Description | Value |
---|---|---|

`Math.E` |
Euler's constant (e) |
2.718281828459045 |

`Math.LN2` |
Natural logarithm of 2 | 0.6931471805599453 |

`Math.LN10` |
Natural logarithm of 10 | 2.302585092994046 |

`Math.LOG2E` |
Base-2 logarithm of e |
1.4426950408889634 |

`Math.LOG10E` |
Base-10 logarithm of e |
0.4342944819032518 |

`Math.PI` |
Ratio of the circumference of a a circle to the diameter (π) | 3.141592653589793 |

`Math.SQRT1_2` |
Square root of 0.5 | 0.7071067811865476 |

`Math.SQRT2` |
Square root of 2 | 1.4142135623730951 |

## String functions

The top-level `String`

property is a collection of functions for manipulating strings.

Function | Description | Example |
---|---|---|

`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)` |
Lowercase the string | `${String.toLowerCase('bEn')} == 'ben'` |

`String.toUpperCase(x)` |
Uppercase the string | `${String.toUpperCase('bEn')} == 'BEN'` |

## Time functions

The top-level `Time`

property is a collection of functions that convert from time values in milliseconds into years, months, days, hours, minutes, and seconds. The examples in the table assume a bound time value T=1567786974710, which in human-readable terms is Friday September 6th, 2019 at 16:22:54 and 710 milliseconds.

Function | Description | Example |
---|---|---|

`Time.year(x)` |
The year | `${Time.year(T)} == 2019` |

`Time.month(x)` |
The month (from 0-11) | `${Time.month(T)} == 8` (September) |

`Time.date(x)` |
The date of the month (1-31) | `${Time.date(T)} == 6` |

`Time.weekDay(x)` |
The day of the week (0-6) | `${Time.weekDay(T)} == 5` (Friday) |

`Time.hours(x)` |
The hour of the day (0-23) | `${Time.hours(T)} == 16` |

`Time.minutes(x)` |
The minutes of the hour (0-59) | `${Time.minutes(T)} == 22` |

`Time.seconds(x)` |
The seconds in the minute (0-59) | `${Time.seconds(T)} == 54` |

`Time.milliseconds(x)` |
The milliseconds (0-999) | `${Time.milliseconds(T)} == 710` |

`Time.format(f, x)` |
A formatted text string | `${Time.format('H:mm', T)} == "16:22"` |

To construct a simple digital clock, the developer could use the Time functions to build a 24-hour clock out of a `Text`

component and the `localTime`

property:

```
{
"type": "Text",
"bind": {
"name": "T",
"value": "${localTime}"
},
"text": "${Time.hours(T)}:${Time.minutes(T)}"
}
```

This example binds the value of `localTime`

into a local variable `T`

to make the text expression a little simpler. This clock renders a time like 4:04 pm as "16:4", which might not be what you want. You can use conditional statements to check the time and include leading/trailing zeros if necessary.

You can also use conditional statement to display a 12-hour clock as shown in this example. This binds both the hours and minutes to local variables, then uses conditional statements to output the time in a 12-hour format with "am" or "pm".

```
{
"type": "Text",
"bind": [
{
"name": "h",
"value": "${Time.hours(localTime)}"
},
{
"name": "m",
"value": "${Time.minutes(localTime)}"
}
],
"text": "${h >= 12 ? h - 12 : h}:${m < 10 ? '0' : ''}${m} ${h >= 12 ? 'pm' : 'am'}"
}
```

You can also use the `Time.format`

function to simplify the code. This example also uses a conditional statement based on hours to add the "am" or "pm" at the end.

```
{
"type": "Text",
"bind": [
{
"name": "h",
"value": "${Time.hours(localTime)}"
}
],
"text": "${Time.format('h:mm', localTime) + (h >= 12 ? ' pm' : ' am')}"
}
```

### Time.format

The `format`

function takes a string argument containing the formatting codes and a time value. The following formatting codes are supported:

Value | Range | Description |
---|---|---|

YY | 00..99 | Year, two digits |

YYYY | 1970..XXXX | Year, four digits |

M | 1..12 | Month (1=January) |

MM | 01..12 | Month, two digits (1=January) |

D | 1..31 | Day of the month |

DD | 01..31 | Day of the month, two digits |

DDD | 0..N | Days, any number of digits |

H | 0..23 | 24h hour |

HH | 00..23 | 24h hour, two digits |

HHH | 0..N | Hours, any number of digits |

h | 1..12 | 12h hour |

hh | 01..12 | 12h hour, two digits |

m | 0..59 | Minutes |

mm | 00..59 | Minutes, two digits |

mmm | 0..N | Minutes, any number of digits |

s | 0..59 | Seconds |

ss | 00..59 | Seconds, two digits |

sss | 0..N | Seconds, any number of digits |

S | 0..9 | Deciseconds |

SS | 00..99 | Centiseconds |

SSS | 000..999 | Milliseconds |

Note that *all* of the formatting codes return digits and digits only.

Here are some examples of the use of the formatting functions, using the time value *September 6th, 2019 at 16:22:54 and 710 milliseconds*.

Format | Value |
---|---|

"DD-MM-YYYY" | 06-09-2019 |

"M/D/YY" | 9/6/19 |

"DDD days" | 18145 days (since the epoch) |

"H:mm" | 16:22 |

"hh:mm" | 04:22 |

"H:mm:ss" | 16:22:54 |

Time formatting also works for relative times from timers. This example uses the value 7523194, which corresponds to *2 hours, 5 minutes, 23.194 seconds*.

Format | Value |
---|---|

"mmm:ss.S" | 125:23.1 |

"HHH:mm:ss.SS" | 2:05:23.19 |

"sss.SSS" | 7523.194 |

For example, to show `elapsedTime`

since the document has loaded:

```
{
"type": "Text",
"text": "${Time.format('mmm:ss.S', elapsedTime)}"
}
```

## 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, then 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'
```