Alexa APL, 第6回　シーケンス(Sequence)を使ったレイアウト 

#はじめに
Alexaを搭載した画面付きデバイスの画面レイアウトを作成します。
今回はSequenceコンポーネントを使って、商品のリストメニューのような画面を作成します。
Sequenceは、商品リストのように同じ情報を繰り返し表示するときに使うものです。
Display Templateでは、ListTempleteと呼ばれていたものかと思います。
Sequenceは繰り返し表示するという点で他のコンポーネントと使い方が異なるため、使い方を整理します。

##今回実施する内容
複数の商品を並べたメニューを作成します。
商品の画像と商品名だけが表示されるシンプルな構成とします。

中型デバイス（Echo Show用）
![中型デバイスレイアウト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/2f51d565-db7c-fbfd-c622-70cc916c2b73.jpeg)

小型デバイス（Echo Spot用）
![小型デバイスレイアウト1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/7cbdd2d2-816d-b178-3c9c-a6f2664e7bf8.jpeg)

#環境
OS:Windows 10 JP
Alexaスキル言語：Node.js
Editor：Visual Studio Code
APLバージョン：1.0, 1.1

#参考
・[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)
第1回のAlexa APLの記事です。タイトル通り、ハローAPLを表示させるだけのAPLです。

#用語
##APL
Alexa Presentation Language
amazonの画面つきのAlexaの画面表示用の言語。
JSONを使用した記載方法です。
インターネットのホームページはHTMLとCSSで作成しますが、AlexaはAPLで作成するということです。

##APLオーサリングツール
APL作成を視覚的に見ながらAPLのJSONファイルを作成するツール。
サンプルテンプレートも準備されており、その中から選択していくだけで、だいたいの画面は作成できる。

#前提条件
前提条件はとくにないといえばないですが、本まとめを読むにあたり、以下がわかっていることが前提です。
・alexa developer consoleのアカウントがある
・Alexaスキルを開発したことがある
・JSONの記載方法を知っている
・「Alexa ハローAPL、Alexaスキルの画面への対応」の記事をみている

#シーケンス（Sequence）を使用した画面レイアウトの作成
##準備
今回の画面レイアウトでは、Sequenceを使って商品をリスト表示するため、3枚の写真とそれにつける商品名を準備します。

|画像|商品名|
|:----|:----|
|coffee_480x480.jpg|コーヒー|
|cappuccino_480x480.jpg|カプチーノ|
|espresso_480x480.jpg|エスプレッソ|

##Sequenceを使って並べてみる
これから作成する「レイアウト画面」はこんな感じです。
![テンプレート構成.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/eca184cd-b73e-2f7c-70e8-62f87965024b.jpeg)

1. APLオーサリングツールを起動して「最初から作成」を選択する。
2. 「レイアウト画面」の「mainTemplate」を選択し、「Container」を追加する。
3. 「レイアウト画面」で、「Container」を選択し、「Sequence」を追加する。
4. 「レイアウト画面」の「Sequence」を選択し、「詳細設定画面」で、以下をそれぞれ設定する。

      ・ data：以下にコード記載。
      ・ height：50vh

      ```json
      "data": [
          {
              "text": "コーヒー",
              "imageURL": "https://coffee_480x480.jpg"
          },
          {
              "text": "カプチーノ",
              "imageURL": "https://cappuccino_480x480.jpg"
          },
          {    
              "text": "エスプレッソ",
              "imageURL": "https://espresso_480x480.jpg"
          }
      ]
      ```

5. 「レイアウト画面」で、「Sequence」を選択し、「Container」を追加する。
6. 「レイアウト画面」の「Container」を選択し、「詳細設定画面」で、以下を設定する。

      ・ direction：row
7. 「レイアウト画面」で、「Container」を選択し、「Image」を追加する。
8. 「レイアウト画面」の「Image」を選択し、以下をそれぞれ設定する。

      ・ source：${data.imageURL}
      ・ height：20vh
9. 「レイアウト画面」で、「Container」を選択し、「Text」を追加する。
10. 「レイアウト画面」の「Text」を選択し、「詳細設定画面」で、以下を設定する。

      ・ text：${data.text}

##APLソースコード
上記で作成されたAPLは以下です。実際にスキルで表示を試す場合は、[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)を参考しましょう。

```json:APLファイル
{
    "type": "APL",
    "version": "1.0",
    "settings": {},
    "theme": "dark",
    "import": [],
    "resources": [],
    "styles": {},
    "onMount": [],
    "graphics": {},
    "commands": {},
    "layouts": {},
    "mainTemplate": {
        "parameters": [
            "payload"
        ],
        "items": [
            {
                "type": "Container",
                "items": [
                    {
                        "type": "Sequence",
                        "data": [
                            {
                                "text": "コーヒー",
                                "imageURL": "https://coffee_480x480.jpg"
                            },
                            {
                                "text": "カプチーノ",
                                "imageURL": "https://cappuccino_480x480.jpg"
                            },
                            {    
                                "text": "エスプレッソ",
                                "imageURL": "https://espresso_480x480.jpg"
                            }
                        ],
                        "items": [
                            {
                                "type": "Container",
                                "direction": "row",
                                "items": [
                                    {
                                        "type": "Image",
                                        "height": "20vh",
                                        "source": "${data.imageURL}"
                                    },
                                    {
                                        "type": "Text",
                                        "text": "${data.text}"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    }
}
```

##JSONデータの作成
上記を実施すると、一番最初に載せた画像通りの出力が得られます。
しかしながら、data部分に直接テキストや画像のリンクを張り付けており、スマートではありません。
データは、JSONデータに作成するのが基本的なAPLの考え方だと思いますので、ソースコードを見直します。

今回はSequenceで渡すデータは、JSONデータを作成します。これにあたり、APL「Sequence」の`data:`の値は、`data: ${payload.sampleArray}`にしました。
単に「準備」のところで記載した内容をJSONに変更するのですが、少し注意が必要でした。
**データJSONの最上位は、配列にすると実際のEchoでは動作しない。**
APLオーサリングツール上では問題なく動作していたのですが、そのままスキルに実装してみるとどうしても、動作しません。
Alexaに「すみません。うまくいきませんでした。」と言われて画面が出ません。


```json:ダメなデータJSON
{
    "sampleArray": [
        {
            "text": "コーヒー",
            "imageURL":"https://coffee_480x480.jpg"
        },
        {
            "text": "カプチーノ",
            "imageURL":"https://cappuccino_480x480.jpg"
        },
        {
            "text": "エスプレッソ",
            "imageURL":"https://espresso_480x480.jpg"
        }
    ]
}
```

```json:ダメなAPL
...
        "mainTemplate": {
            "parameters": [
                "payload"
            ],
            "items": [
                {
                    "type": "Container",
                    "items": [
                        {
                            "type": "Sequence",
                            "height": "50vh",
                            "data": "${payload.sampleArray}",
                            "items": [
                                {
                                    "type": "Container",
                                    "direction": "row",
                                    "items": [
                                        {
                                            "type": "Image",
                                            "height": "20vh",
                                            "source": "${data.imageURL}"
                                        },
                                        {
                                            "type": "Text",
                                            "text": "${data.text}"
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
...
```

ということで、色々試した結果、最上位の要素を配列ではなく、一段要素を加えれば、実機のEchoでも動作することがわかりました。


```json:実機で動作するデータJSON
{
    "sample": {    //ここにダミーの階層を追加
        "sampleArray": [
            {
                "text": "コーヒー",
                "imageURL": "https://coffee_480x480.jpg"
            },
            {
                "text": "カプチーノ",
                "imageURL": "https://cappuccino_480x480.jpg"
            },
            {
                "text": "エスプレッソ",
                "imageURL": "https://espresso_480x480.jpg"
            }
        ]
    }
}
```

```json:実機で動作するAPL
...
        "mainTemplate": {
            "parameters": [
                "payload"
            ],
            "items": [
                {
                    "type": "Container",
                    "items": [
                        {
                            "type": "Sequence",
                            "height": "50vh",
                            "data": "${payload.sample.sampleArray}",   //ここにダミーのsample追加
                            "items": [
                                {
                                    "type": "Container",
                                    "direction": "row",
                                    "items": [
                                        {
                                            "type": "Image",
                                            "height": "20vh",
                                            "source": "${data.imageURL}"
                                        },
                                        {
                                            "type": "Text",
                                            "text": "${data.text}"
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
...
```

##Sequenceの補足
Sequenceは、繰り返しデータを並べる目的のコンポーネントであることから、「繰り返しするためのレイアウト」をSequenceコンポーネントの直下に作成して、「データ」をSequenceに配列で渡すと繰り返して表示します。

###繰り返すデータ
繰り返す「データ」は、Sequenceの「data」プロパティに配列として設定します。
今回でいえば、「${payload.sample.sampleArray}」であり、JSONデータに配列を記載しました。
若干癖があるように思います(最上位が配列では動作しない)が、`sampleArray`が配列で`[]`でくくり、その配下は、JSONとして`{}`で区切って記載する必要があるようです。

###レイアウト
今回作成した例では、「繰り返しするためのレイアウト」は、以下の図の赤枠の部分です。
![テンプレート構成2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/2a82d88d-3179-ad05-aa0c-0bcd2053e699.jpeg)


「Container」をいれて、「Image」と「Text」の配置が行方向（direction：row）になるようにしています。
「Image」の「source」や「Text」の「text」には、「データ」からのパスを記載しており、`${data.imageURL}`や`${data.text}`です。
`data`は、Sequenceのプロパティの`data`のことであり、多分固定値と思います。
`text`や`imageURL`は、JSONデータ上のパスです。

今回、Sequenceの`height: 50vh`で、Imageの`height: 20vh`に設定しました。
これは、Imageが3つあるためトータルで60vhになりますが、その場合、Sequenceはどうなるのか？を確認するために試しました。
結果としては、Sequenceの高さは50vhになっており、エスプレッソの画面は少し切れました。この部分はスクロールすることが可能でした。

###変数について
Sequenceを利用する場合、dataプロパティに値を設定しますが、これはプログラミングでいうところの変数と同じです。
dataプロパティに、繰り返すデータの配列の変数を記載しているわけですが、関係がわかるように図示しました。
今回はもっともシンプルになるように構成して作成しましたが、これがレイアウトが複雑になり、mainTemplateではなく、layoutsに記載して多重でレイアウトを構成するようになるとこの変数がどこを示すのかよくわからなくなるため注意が必要です。
![変数の関係.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/b00fbb20-4eb1-420b-20b7-167ea4be5aab.jpeg)

##APLソースコードとデータJSON
最後に今回作成したAPLのフルソースコードとデータJSONを載せます。実際にスキルで表示を試す場合は、[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)を参考しましょう。

```json:APL
{
        "type": "APL",
        "version": "1.1",
        "settings": {},
        "theme": "dark",
        "import": [],
        "resources": [],
        "styles": {},
        "onMount": [],
        "graphics": {},
        "commands": {},
        "layouts": {},
        "mainTemplate": {
            "parameters": [
                "payload"
            ],
            "items": [
                {
                    "type": "Container",
                    "items": [
                        {
                            "type": "Sequence",
                            "height": "50vh",
                            "data": "${payload.sample.sampleArray}",
                            "items": [
                                {
                                    "type": "Container",
                                    "direction": "row",
                                    "items": [
                                        {
                                            "type": "Image",
                                            "height": "20vh",
                                            "source": "${data.imageURL}"
                                        },
                                        {
                                            "type": "Text",
                                            "text": "${data.text}"
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    }
```

```json:データJSON
{
        "sample": {
            "sampleArray": [
                {
                    "text": "コーヒー",
                    "imageURL": "https://coffee_480x480.jpg"
                },
                {
                    "text": "カプチーノ",
                    "imageURL": "https://cappuccino_480x480.jpg"
                },
                {
                    "text": "エスプレッソ",
                    "imageURL": "https://espresso_480x480.jpg"
                }
            ]
        }
    }
```

#まとめ
今回は、Sequenceを使って、繰り返しデータを表示する方法を説明しました。
JSONデータを使用する場合、最上位には配列ではなく、1つ以上の要素が必要なことに注意する必要があります。