Conditional Component Inflation (APL for Audio)

Conditional component inflation determines which components to render in an APL document. For example, the mainTemplate property of an APL document accepts an array of components in the items property, but renders a single component. Conditional component inflation determines which one to render. The component inflation algorithms enable lightweight conditional expressions using arrays of components, the when property in primitive components, and data-binding.

Conditional inflation scenarios

Conditional inflation works differently depending on the scenario:

  • Single child – Alexa renders a single component from an array of possible components.
  • Simple array – Alexa renders a subset of components from an array of components.
  • Data array – Alexa uses a data array to render a set of components.

The remaining sections provide more details about each of these scenarios.

Single child inflation

With single child inflation, Alexa renders at most one child component from an array of components. For example, the mainTemplate in an APL document might have multiple components in the items array, but Alexa renders one single component from the array.

Used by

Components that accept an array of components in items, but inflate a single child. This includes:

  • mainTemplate.items property on a document.
  • Selector

Algorithm

Given an array of components, evaluate the when property of each component in turn. Render the first component with a when property that evaluates to true. If no component in the array has a true when property, no component is inflated. When the when property is omitted for a component, it defaults to true.

Data-binding

By default, no additional properties are bound for single child inflation. For the Selector component, when you set the data property, the data-binding context is extended with the data, index, and length properties. See the Selector component for details.

The following example shows a Selector component. Selector renders a single child component, but takes an array of components in the items property.

Copied to clipboard.

{
  "type": "Selector",
  "items": [
    {
      "when": "${payload.myData.userDefinedList.length > 1}",
      "type": "Speech",
      "contentType": "PlainText",
      "content": "Say this when userDefinedList has more than one item."
    },
    {
      "type": "Speech",
      "contentType": "PlainText",
      "content": "Say this when userDefinedList has one item or no items."
    }
  ]
}

Alexa renders the first Speech component when the array defined by payload.myData.userDefinedList contains more than one one item. Alexa renders the second Speech component when the array has zero items or one item. The when property defaults to true when not specified, so in this example, the second Speech always renders if the first component is skipped.

For example, with the following data source, the Selector creates an audio clip with the speech "Say this when userDefinedList has more than one item."

Copied to clipboard.

{
  "myData": {
    "userDefinedList": [
      "item 1",
      "item 2",
      "item 3"
    ]
  }
}

The following alternate data source creates an audio clip with the speech "Say this when userDefinedList has one item or no items."

Copied to clipboard.

{
  "myData": {
    "userDefinedList": [
      "item 1"
    ]
  }
}

Simple array inflation

With simple array inflation, Alexa renders a subset of components from an array of components. For example a Sequencer component accepts an array of components in the items property. Alexa renders all the items in the array, or a subset of items.

Use a simple array of items when you have a collection of heterogeneous items to render in a multiple-child component.

Used by

Multiple-child components when the data property isn't set:

Algorithm

The when property of each component in the array is evaluated. If the when property evaluates to true, Alexa adds the to the array of children to render.

Data-binding

The index and length values are bound. For more details, see Component child extension

The following example shows a Sequencer component, which renders multiple components one after another. In this example, the data property is omitted, so the component uses the simple array approach to evaluate all the components in items and choose the subset to render.

Copied to clipboard.

{
  "type": "Sequencer",
  "items": [
    {
      "type": "Speech",
      "content": "hello world."
    },
    {
      "type": "Speech",
      "when": "${environment.aplVersion}",
      "content": "Check your screen for the daily greeting!"
    }
  ]
}

The environment.aplVersion property returns the version of APL supported by the device. It returns null on a device that doesn't have a screen or otherwise doesn't support APL for screen devices. Therefore, in this example:

  • When the device has a screen, the Sequencer renders both components and the user hears "Hello world! Check your screen for the daily greeting!"
  • When the device doesn't have a screen, the Sequencer renders the first component and ignores the second, so the user hears "Hello world!"

Data array inflation

With data array inflation, Alexa uses an array of data to inflate a set of components. This method is available for multiple-child components when the data property is set.

Use the data array approach when you have an array of data that you want to concatenate together. You define the set of components to render. Alexa renders that set of components for each item in data.

Used by

Multiple-child components when the data property is set:

Algorithm

Each element in the data array is bound in turn to the variable "data" in the data-binding context. For each bound element, Alexa uses the single child algorithm to find a single component to render.

Data-binding

The data, index, and length values are bound. For more details, see Component child extension

The following example illustrates a Sequencer component with the data property set to an array of strings representing the steps of a recipe. The component then has a single component in item that uses the data variable to render content from the data array.

Copied to clipboard.

 {
  "type": "Sequencer",
  "item": {
    "type": "Speech",
    "content": "${index+1}. ${data}"
  },
  "data": "${payload.recipeData.steps}"
}

This example uses the following data source to provide the array of data to the data property.

Copied to clipboard.

{
  "recipeData": {
    "steps": [
      "Preheat the oven to 350 degrees F.",
      "Blend the butter and sugar in a mixer until smooth.",
      "Add one egg at a time to the butter-sugar mixture and beat until smooth.",
      "In a separate bowl, combine...."
    ]
  }
}

Alexa evaluates the single Speech component one time for each string in data. If the when property evaluates to true, Alexa renders the component. In this example, the when property defaults to true, so Alexa renders the component four times, one time for each string in data. The user hears all four strings, one after the other.

A more complicated example uses when statements and nests Sequencer components to inflate a heterogeneous set of data.

Copied to clipboard.

{
  "type": "Sequencer",
  "items": [
    {
      "when": "${data.opening}",
      "type": "Speech",
      "content": "${data.opening}"
    },
    {
      "type": "Sequencer",
      "items": [
        {
          "type": "Speech",
          "content": "${data.speech1}"
        },
        {
          "type": "Speech",
          "content": "${data.speech2}"
        }
      ]
    }
  ],
  "data": "${payload.speechData}"
}

This example uses the following data source to provide the array of data to the data property.

Copied to clipboard.

{
  "speechData": [
    {
      "opening": "opening speech"
    },
    {
      "speech1": "first thing",
      "speech2": "second thing"
    }
  ]
}

Alexa evaluates the Sequencer one time for each of the two items in data:

  • The first item is object with an opening property. Alexa selects the first Speech component since ${data.opening} is true. The nested Sequencer with the two Speech components is effectively ignored because the data.speech1 and data.speech2 values are both empty.
  • The second item is an object with speech1 and speech2 properties. Alexa ignores the first Speech component since ${data.opening} is false. The nested Sequencer is inflated using the simple array of child components, so Alexa renders both Speech components.

The end result is the speech "opening speech first thing second thing".