Bixby's Expression Language (EL) allows you to work with your capsule's concepts and actions in layouts, strategies, and dialogs by using simple expressions.
Here's an example of a simple layout including Expression Language:
layout {
mode (Summary)
match: Recipe (this)
content {
section {
title {
template ("#{value(name)}")
}
content {
if (exists(totalTime)) {
single-line {
text {
value ("Total Time: #{value(totalTime)} minutes")
}
}
}
if (exists(recipe.servings)) {
single-line {
text {
value ("Servings: #{value(servings)}")
}
}
}
}
}
}
}
Recipe
to the variable this
. Many EL functions that access slots (properties on a concept or inputs on an action) will look for them on this
if no variable is specified.this
are accessed with the .
operator, as seen in this.name
.exists(totalTime)
is used to check whether the slot this.totalTime
has a value. If the match
expression had bound Recipe
to a name other than this
, it would need to be explicitly specified here. So, if the match pattern had been Recipe (r)
, we would have had to use˙ exists(r.totalTime)
.#{}
notation: #{value(totalTime)}
returns the value of this.totalTime
.Expression Language includes functions for testing node values, formatting them in a variety of ways in templates, working with geospatial information, and more. For a full list of EL functions, read the Expression Language Reference.
EL provides a set of typical operators you can use in expressions for comparisons, mathematics, and logic.
+
, -
, *
, /
, %
(modulo division), div
, mod
, unary -
and
, &&
, or
, ||
, not
, !
==
, eq
, !=
, ne,
<
, lt
, >
, gt
, <=
, le
, >=
, ge
.empty
prefix operator can be used to determine whether a value is null
or empty.A ? B : C
. Evaluate to B
if A
is true, otherwise evaluate to C
. A shorthand equivalent to if (a) then return b else return c
.Comparisons can be made against other values or against Boolean, string, integer, or floating-point literals.
if (size(legs) == 1) {
template ("Nonstop")
} else {
template ("#{integer(size(legs) -1)} stops")
}
Here is a more complex example that uses logic, comparisons, and ternary conditionals:
template("#{value(info.Prop1)} #{(exists(info.Prop1Val) && info.Prop1Val > -1 ? info.Prop1Val : 'empty')}")
The ternary conditional in this example is specifically this statement: exists(info.Prop1Val) && info.Prop1Val > -1 ? info.Prop1Val : 'empty'
. The entire template
will print both the value of info.Prop1
and info.Prop1Val
, if info.Prop1Val
exists and has a value greater than -1. The template
will print just info.Prop1
otherwise. This is a convenient way to have a template dynamically print information.
A slot can be either of the following:
sum
property on the RollResult
concept in the Dice sample capsule in the Quick Start Guide.Slots can be accessed in one of two ways:
.
operator: node.slot
[ ]
operator: node['slot']
if (this.description == 'NoMatchedAlarm') {
// description slot on the node bound to "clock" is equal to 'NoMatchedAlarm'
}
You can also use the .
operator to refer to symbol values in enums. In this example, textposition
is an enum
:
image-card {
aspect-ratio (4:3)
image-url ("[#{value(param.image.url)}]")
// either
text-position (Overlay) // can only be one of the allowed values [Below, Overlay]
// or
text-position {
if (param.textposition == 'cover') {
value (Overlay) // can only be one of the allowed values [Below, Overlay]
} else {
value (Bottom) // can only be one of the allowed values [Below, Overlay]
}
}
The bracket operator for accessors should be used with single-quoted strings rather than double-quoted strings.
Do: value(this['property'])
Don't: value(this["property"])
Expression Language can be used with certain keys: match patterns, conditionals such as if
blocks, and inside strings. In addition, the values returned by EL expressions can be bound using the $expr()
construct.
In this example, moon.MoonPhase
is bound to this
, and the name
property is accessed with the .
operator:
match: moon.MoonPhase (this)
if (exists(this.name) && this.name == 'New Moon') {
...
}
In this example, #{}
is used to inject an EL expression into advice:
match: time.DateTime (time)
advice ("#{isPast(time) ? 0.1 : 0.9}")
You might see EL embedded in strings using either #{}
or ${}
. The first form is similar to Ruby's ERB and other template languages; the second form is the Unified Expression Language standard. There is no difference in functionality between the two forms.
Lastly, this code example binds time.Date
to date
and the output of the moon.GetMoonPhaseDate
action to action
, and uses both of them in a dialog macro
expression.
match: time.Date (date) {
from-output: moon.GetMoonPhaseDate(action)
}
...
expression("The next #{value(action.moonName)} is on #{value(date)}")
The $expr()
construct takes an EL expression as an argument and returns its value. This can be used in a typed or untyped form. This example, from the sample transactional capsule, comes from the GetSize
constructor
action:
action (GetSize) {
type (Constructor)
collect {
input (size) {
type(Size)
min(Required)
max(One)
plan-behavior (Never)
prompt-behavior (AlwaysSelection)
//Lists all available options
default-init {
intent {
goal: Size
value-set: Size { Size(ExtraSmall) Size(Small) Size(Medium) Size(Large) Size(ExtraLarge) }
}
}
}
}
output (PromptedSize) {
evaluate { $expr(size) }
}
}
The typed expression form of $expr()
lets you coerce the returned value to a specific concept. For instance, the following view coerces the value of query
to be a location.SearchTerm
:
input-view {
match: DestinationPoint
message ("Where would you like to go?")
render {
macro (location:Autocomplete) {
param (noResultText) {
dialog-template ("No results")
}
param (placeholder) {
dialog-template ("Search for locations")
}
select-button-text {
template ("Ok")
}
}
}
}
There are several variables available in EL that can be used to access contextual information about the user and device.
Suppose you wanted to set a concept's value to the user's current location. You could set a myLocation
concept to that value by creating an action file that takes this computed-input
block:
computed-input (myLocation) {
min (Required) max(One)
type (geo.CurrentLocation)
compute {
if (exists($user.currentLocation)) {
intent {
goal: geo.CurrentLocation
value-set: geo.CurrentLocation { $expr($user.currentLocation) }
}
}
}
}
Your capsule will need to request the device-location-access
permission to be able to access the user's CurrentLocation
. For more information, read the Grant Capsule Permissions Developers' Guide.
For a list of special EL variables, read the Expression Language Reference.
Bixby Developer Studio will highlight Expression Language constructs when they appear in Bixby Language files, and provide real-time validation.