APL Bound Variables
All Alexa Presentation Language (APL) components, layouts, and Alexa Vector Graphics (AVG) support bound variables. A bound variable is a local variable that your document can access from the data-binding context of the component and its children. For a layout, the bound variable is attached to the component that the layout inflates into.
Use the bind
property to define a bound variable on a component, layout, or vector graphic. The bind
property accepts an ordered array of binding objects that extend the data-binding context.
Evaluation of the bind property
The bind
property evaluates after the when
property and before any other properties on the component, layout, or AVG. Bindings are added to the data-binding context in array order. A later binding can use previous bindings in its definition, as shown in the following example.
{
"type": "Text",
"bind": [
{ "name": "FirstName", "value": "Jasmine" },
{ "name": "LastName", "value": "Smith"},
{ "name": "Title", "value": "Dr."},
{ "name": "FormalName", "value": "${Title} ${LastName}" }
],
"text": "Should I call you ${FirstName} or ${FormalName}?"
}
In this example, FormalName
depends upon the earlier definitions of Title
and LastName
. The final text is "Should I call you Jasmine or Dr. Smith?" This example is contrived. In actual use, you would likely bind the values of FirstName
, LastName
, and Title
to elements provided in the raw data.
You can change binding values dynamically with the SetValue
command.
Bind object properties
Each object in the bind
array contains the following properties.
Property | Type | Default | Description |
---|---|---|---|
|
String |
Required |
Name to use for this binding. Must be a valid name. You use this name to refer to the variable in data-binding expressions. |
|
Any |
Required |
Value to assign to this binding. When the |
|
Type |
any |
Type of value to store in the binding. |
|
Array of commands |
|
Commands to run when this binding changes value. Not available in AVG |
name
The name to use for this binding. The name must be valid data binding identifier.
SetValue
command can change the value of both component properties and bindings, capitalize your bound property names. This prevents conflicts with intrinsic component properties. For example, use MyCounter
or MY_COUNTER
instead of myCounter
.type
The data type for this binding. The default type is any, which means that you can set the value
to anything. Specify a type to coerce the binding into that type.
In the following example, the value of Test
is true
because the variable is a boolean
and 23.4
is a non-zero number.
{
"name": "Test",
"value": 23.4,
"type": "boolean"
}
For more about how data binding coerces values into different types, see Truthy and coercion.
value
The value to assign to the binding. This value is coerced to the specified type
if necessary. This assignment is evaluated when the binding is first created and whenever any variable used within the binding changes.
The following example defines two bound variables, COUNT
and STRING
.
{
"bind": [
{
"name": "COUNT",
"value": 1
},
{
"name": "STRING",
"value": "The count is ${COUNT}"
}
]
}
Each time the bound value COUNT
changes, such as with the SetValue
command, the bound value STRING
updates as well.
onChange
Requires APL 2024.1 or later.
The onChange
event handler runs when the bound value changes in a component or layout. The onChange
event handler isn't available in AVG items.
The onChange
handler runs in fast mode. The event generated has the following form.
{
"event": {
"source": {
"type": "COMPONENT_TYPE", // The type of the component or AVG item, such as "Pager", or "TouchWrapper"
"handler": "Change"
},
"current": "VALUE", // The current value of the binding
"previous": "VALUE" // The previous value of the binding
}
}
A common use of the onChange
event handler is to respond to changes in live data provided by an extension. For example if the FishFeeder
extension provides a live data object named TankTemperature
, then you can use an onChange
handler to track the minimum and maximum fish tank temperatures.
{
"type": "Text",
"bind": [
{
"name": "MIN_TEMP",
"value": null
},
{
"name": "MAX_TEMP",
"value": null
},
{
"name": "TEMP",
"value": "${TankTemperature}",
"onChange": [
{
"type": "SetValue",
"property": "MIN_TEMP",
"value": "${MIN_TEMP == null || TEMP < MIN_TEMP ? TEMP : MIN_TEMP}"
},
{
"type": "SetValue",
"property": "MAX_TEMP",
"value": "${MAX_TEMP == null || TEMP > MAX_TEMP ? TEMP : MAX_TEMP}"
}
]
}
],
"text": "Current Temperature=${TEMP} Low=${MIN_TEMP} High=${MAX_TEMP}"
}
For details about live data in extensions, see Extension live data.
The onChange
event handler isn't re-entrant. If a command in the onChange
handler changes the value of the binding that triggered the onChange
handler, the onChange
handler isn't called again.
The following example shows a TouchWrapper
component with a COUNTER
bound variable.
{
"type": "TouchWrapper",
"bind": [
{
"name": "COUNTER",
"value": 0,
"onChange": {
"type": "SetValue",
"property": "COUNTER",
"value": "${COUNTER+1}"
}
]
},
"onPress": {
"type": "SetValue",
"property": "COUNTER",
"value": 1
}
}
Tapping the TouchWrapper
sets COUNTER
to 1
, and the triggers the onChange
event handler, which sets the COUNTER
to 2
. At this point, the command stops because you can't trigger the onChange
event handler from within itself.
Bound variable example
The following example displays a counter with buttons to increment and decrement the count. A bound variable called COUNTER
stores the current value of the counter and uses onChange
to update a Text
component each time the value changes. The onChange
handler also runs commands to change the color of the counter based on whether it's positive, negative, or zero.
Related topics
Last updated: Feb 14, 2024