Power Apps で注文送信画面を作成する


# はじめに

例えば、データソースとしては、以下のように注文と注文明細を分けて管理し、ID で紐づけ、こちらのデータソースにデータを送信する注文するアプリを作りたいとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/c8dbfdab-560d-908f-4d0f-20c689a59da6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/eb426981-f3c2-4459-ed64-fe871aba3e1e.png)

この場合、案件ごとに注文明細の数が異なるため、入力個数を動的に変更でき、また、注文と注文明細で矛盾が生じないようにデータ登録したいといった要件が考えられます。

今回は、そのような要件を満たす、以下のような画面でデータ登録をする方法について紹介します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/558da1c9-d5f0-ccca-60fd-c63ae118ab8a.png)

# データソースの用意


上述したようなデータソースを作成します。注文テーブルの ID 列と注文明細の注文 ID を紐づけます。

※今回は、アプリ側で矛盾が生じないようにデータ登録をします。Dataverse の時はリレーションシップを設定しても良いかと思います

# 入力画面の作成

入力画面を段階的に作成していきます。

部品の全体像は以下のような感じです。
今回は体裁を整えるためコンテナベースで作成しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/0da0049b-8f29-0ad2-e3ce-4a9f3758c1df.png)

ポイントとなるところをもう少し詳しく説明します。

## コレクションの作成

`[App]`の`[OnStart]`にて以下のようなコレクションを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/6574a039-c41a-249e-fdf8-682795cfdb85.png)

コレクションに格納する情報は、注文詳細側の列の情報がベースになります。
今回は、以下の 3 つです。

```
ClearCollect(
    colOrderItems,
    {
        品物: "",
        単価: "",
        数量: ""
    }
)
```

## ヘッダーの作成

こちらのコンテナーにラベルを 3 つ配置します。
`[With]`プロパティを Parent.Width/3 にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/b0116be4-d173-a050-dadc-e8fe93d448e1.png)

## ギャラリーの設定

ギャラリーを追加し、`[Items]`プロパティを先ほど作成したコレクションにします。
テキスト入力コントロールを 3 つ、アイコンを一つ追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/ddd9a908-4488-e428-98d2-f280d5b8e121.png)

それぞれのサイズについて、ヘッダーと大体合うようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/1711d0da-f2b3-856a-0e49-d92bb9c3975f.png)

そして、テキスト入力コントロールの`[OnChange]`プロパティを以下のように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/14b80196-3179-c0cb-3147-c38bc37aba74.png)

```
Patch(
    colOrderItems,
    ThisItem,
    {品物: txtItem.Text}
)
```

※txtItem はテキスト入力コントロールの名前です

また、`[Default]`プロパティを以下のようにします。
品物の箇所については、ThisItem.品物 といった感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/fdd3020b-4aa0-e276-b8d6-f1e7210218ff.png)

3 つのテキスト入力コントロールについて、同じように`[OnChange]`、`[Default]`プロパティを設定していきます。

■単価のテキスト入力コントロールの`[OnChange]`
```
Patch(
    colOrderItems,
    ThisItem,
    {単価: txtUnitPrice.Text}
)
```

■数量のテキスト入力コントロールの`[OnChange]`

```
Patch(
    colOrderItems,
    ThisItem,
    {数量: txtQuontity.Text}
)
```

※`[Default]`プロパティについては割愛します

また、プラスのアイコンを配置し、`[OnSelect]`プロパティに以下の処理を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/f518388d-cd37-eeaa-95cd-ab4e9dc06131.png)

```
Collect(
    colOrderItems,
    {
        品物: "",
        単価: "",
        数量: ""
    }
);
```

ギャラリーにゴミ箱アイコンを追加し、`[OnSelect]`プロパティに以下の処理を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/c18b039d-d775-726b-dc06-cdd9afa91ee6.png)

```
Remove(colOrderItems,ThisItem)
```

# データ送信

最後に、送信ボタンを作成し、`[OnSelect]`プロパティに以下の処理を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8b1f8751-4bf6-6c04-cd5f-fb79d9c3d36f.png)

```
Set(
    gblOrderId,
    Patch(
        注文,
        Defaults(注文),
        {
            タイトル: TextInput1.Text,
            日付: DatePicker1.SelectedDate
        }
    ).ID
);
If(
     // エラー判定
    !IsEmpty(Errors(注文)),
     // エラーメッセージ
    Notify(
        Concat(
            Errors(注文),
            Column & ": " & Message
        ),
        NotificationType.Error
    ),
      //注文明細
    ForAll(
        colOrderItems,
        Patch(
            注文明細,
            Defaults(注文明細),
            {
                注文ID: Value(gblOrderId),
                タイトル: ThisRecord.品物,
                単価: Value(ThisRecord.単価),
                数量: Value(ThisRecord.数量)
            }
        )
    );
    // 成功メッセージ
Notify(
        "注文の送信処理が成功しました",
        NotificationType.Success
    );
    ClearCollect(
        colOrderItems,
        {
            品物: "",
            単価: "",
            数量: ""
        }
    );
    Reset(TextInput1)
);

```

ポイントは、先に注文テーブルにデータを送信し、そちらの ID 列を変数に格納した上で注文詳細テーブル側にデータを送信するところです。
これにより、注文詳細テーブル側の '注文 ID' が注文テーブル側の該当の注文の ID となります。

実行したところ、問題なくデータの登録が出来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/6aa7eaaf-5dc5-cf0c-1b0f-771f2dab3da1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/26a3354e-de73-0275-cb9a-fb81b8b1fa14.png)

# 別のアプローチ

書いた後に気づいたのですが、以下のアプローチでも良いと思います。
ポイントは、`Gallery1_1.AllItems`を利用することです。この場合、ギャラリーの各行に対して処理をする感じになります。そのため、ギャラリー内の各コントロールの`[Text]`プロパティを登録する感じになります。この場合、各コントロールの`[Default]`プロパティや`[OnChange]`プロパティを設定する必要はないため、手順が少し楽になると思います。

```
Set(
    gblOrderId,
    Patch(
        注文,
        Defaults(注文),
        {
            タイトル: TextInput1_2.Text,
            日付: DatePicker1_2.SelectedDate
        }
    ).ID
);
If(
     // エラー判定
    !IsEmpty(Errors(注文)),
     // エラーメッセージ
    Notify(
        Concat(
            Errors(注文),
            Column & ": " & Message
        ),
        NotificationType.Error
    ),
      //注文明細
    ForAll(
        Gallery1_1.AllItems,
        Patch(
            注文明細,
            Defaults(注文明細),
            {
                注文ID: Value(gblOrderId),
                タイトル: ThisRecord.TextInput2_3.Text,
                単価: Value(ThisRecord.TextInput2_4.Text),
                数量: Value(ThisRecord.TextInput2_5.Text)
            }
        )
    );
    // 成功メッセージ
Notify(
        "注文の送信処理が成功しました",
        NotificationType.Success
    );
    ClearCollect(
        colOrderItems,
        {
            品物: "",
            単価: "",
            数量: ""
        }
    );
    Reset(TextInput1_2)
);

```


# まとめ

今回は、注文テーブルと注文明細テーブルが分かれており、注文明細側の行数が動的な場合における Power Apps 側での注文送信画面を作成する方法について紹介しました。

やや難しいと思いますが、結構需要のあるデータ入力の仕方かと思います。
このような画面で作成したいという方のお役に立てば幸いです。