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.