Power Apps で勤務シフト作成アプリを作る その３ まだ必要な基本機能実装編

本記事は5回シリーズ（の予定）です。
その１はこちら：https://qiita.com/KodamaJn/items/afc40f565aca772ab67f
その２はこちら：https://qiita.com/KodamaJn/items/a16e7bb021780e51850d
その３はこちら：本記事
その４はこちら：https://qiita.com/KodamaJn/items/2765f395d807de13f785
その５はこちら：執筆中…

　その３では、その２で作成したアプリをまともに利用できるように改良していきます。

# アプリにまだ必要な基本機能を実装する
## 保存を Collection 経由にする
　その２で"最低限"勤務パターンを勤務者毎に設定する機能は完成したものの、その２の状態ではドロップダウンで各勤務者＆各日の勤務パターンを変更する度に SharePoint リストへの書き込みアクセスが発生するため、書き込みが追い付かずエラーとなります。
　そこで、ドロップダウンを変更した時点では内部のコレクションにデータを貯めておき、後で一気に SharePoint リストに書き込む方法に改良します。
　コレクションの概要については、 Microsoft MVP 太田さんの記事が個人的に分かりやすくておススメです。
　[おぼえておくと便利そうな PowerApps の変数やコレクションの基礎](https://idea.tostring.jp/?p=4121)

　まずは、App の OnStart に、今月一か月分の全データを SharePoint リストからコレクション ShiftData に格納する処理を追記します。日付列のフィルタリングは委任できませんので、委任回避用に用意した日付数値列でフィルタリングします。

```:OnStart(追記分のみ)
ClearCollect(ShiftData, Filter(勤務シフト_メイン, mWorkDateValue>=Value(Text(FirstDayOfMonth, "[$-ja]yyyymmdd")), mWorkDateValue<=Value(Text(FirstDayOfMonth+DaysOfMonth-1, "[$-ja]yyyymmdd"))));
```

![スクリーンショット (59).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/430c9a4f-67a5-1e46-2668-d3241dca0b3e.png)
　追記したら、OnStart を実行しておきましょう。

　この一か月分のデータ格納処理は、月を切り替える際にも必要となりますので、先月に切り替えるアイコン IconPrevMonth と次月に切り替えるアイコン IconNextMonth の OnSelect にも、先ほどと同じ処理を追記します。

```:OnSelect(追記分のみ)
ClearCollect(ShiftData, Filter(勤務シフト_メイン, mWorkDateValue>=Value(Text(FirstDayOfMonth, "[$-ja]yyyymmdd")), mWorkDateValue<=Value(Text(FirstDayOfMonth+DaysOfMonth-1, "[$-ja]yyyymmdd"))));
```

![スクリーンショット (61).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/c9cc9499-aa40-5cb1-e26f-4e9b8ec2e689.png)
![スクリーンショット (62).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/f61cd511-424a-0471-262e-473d8d09ea96.png)

　続いて、ドロップダウンの設定変更へ。
　まずは初期値の参照先を SharePoint リストからコレクションに変更します。データソースの部分を ShiftData に書き換えるだけです。

```:DropdownWorkPattern-Default
First(Filter(ShiftData, mWorkDateValue=Value(LabelDayValue.Text), mWorkUser.DisplayName=ThisItem.uWorkUser.DisplayName)).mWorkPattern
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/d97961f6-d72d-5d9d-e625-fa659c0f4ebc.png)

　続いて、ドロップダウンを変更した際の書き込み先を SharePoint リストからコレクションに変更します。こちらも、データソースの部分を ShiftData に書き換えるだけです。

```:DropdownWorkPattern-OnChange
If(IsEmpty(Filter(ShiftData, mWorkDateValue=Value(LabelDayValue.Text), mWorkUser.DisplayName=ThisItem.uWorkUser.DisplayName)),
    Patch(ShiftData, Defaults(ShiftData), {mWorkDate: DateAdd(FirstDayOfMonth, Value(LabelDay.Text)-1,Days), mWorkDateValue: Value(LabelDayValue.Text), mWorkUser:ThisItem.uWorkUser, mWorkPattern: DropdownWorkPattern.Selected.pWorkPattern}),
    UpdateIf(ShiftData, And(mWorkDateValue=Value(LabelDayValue.Text),mWorkUser.DisplayName=ThisItem.uWorkUser.DisplayName), {mWorkPattern: DropdownWorkPattern.Selected.pWorkPattern})
);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/a8d38983-1c2f-f003-7652-c367048fb569.png)

　最後に、コレクションのデータを一気に SharePoint リストに書き込むための処理を追加します。
　まずは保存アイコン IconSaveToList を追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/48449fff-b58a-f935-c99b-382a6aeb042d.png)

　そして、OnSelect に以下の処理を追記します。ドロップダウンの OnChange に似た処理が、ForAll 関数と AddColumns 関数で囲われている構造です。

```:IconSaveToList-OnSelect
ForAll(
    AddColumns(ShiftData, 
        "sWorkDate", mWorkDate,
        "sWorkDateValue", mWorkDateValue,
        "sWorkUser", mWorkUser,
        "sWorkUserName", mWorkUser.DisplayName,
        "sWorkPattern", mWorkPattern
    ),
    If(IsEmpty(Filter(勤務シフト_メイン, mWorkDateValue=sWorkDateValue, mWorkUser.DisplayName=sWorkUserName)),
        Table(Patch(勤務シフト_メイン, Defaults(勤務シフト_メイン), {mWorkDate: sWorkDate, mWorkDateValue: sWorkDateValue, mWorkUser:sWorkUser, mWorkPattern: sWorkPattern})),
        UpdateIf(勤務シフト_メイン, And(mWorkDateValue=sWorkDateValue, mWorkUser.DisplayName=sWorkUserName), {mWorkPattern: sWorkPattern})
    )
);
```

![スクリーンショット (66).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/824949c1-0c2c-2e03-4c06-9207934f6ed6.png)
　ちょっと複雑なので解説します。

　まず、複数のレコードをまとめて処理したいので、ForAll 関数を使用します。
　[Power Apps での ForAll 関数](https://docs.microsoft.com/ja-jp/powerapps/maker/canvas-apps/functions/function-forall)

　そして、ここのポイントは、AddColumns です。

　ここではコレクションの各列の値を SharePoint リストの各列に格納したいのですが、そもそもコレクションは SharePoint リストから取得したものなので、列名が一緒なんですよね。
　そのため、素直にコレクションと SharePoint リストの列を比較したり値を代入したりするには `mWorkDate=mWorkDate` や `mWorkDate:mWorkDate` のように左辺と右辺の列名を同じにする必要があるのですが、残念ながらこれではコレクションと SharePoint リストのどっちの列のことを言っているのか、Power Apps が理解してくれないようです。
　そこで、コレクション側に AddColumns を用いて同じ値を持つ別の名前の列を追加し、それと SharePoint リストの列を比較・代入する方法を用いています。
　この方法は、Microsoft MVP 前田さんの以下の記事を丸々参考にさせていただきました。
　[Power Apps ForAll + Patch で複数レコードを一括更新する](https://zezeze.hateblo.jp/entry/2020/01/09/005545)

　あと補足ですが、AddColumns の後の SharePoint リストの更新処理で、Patch 関数を Table 関数で囲っていますが（これまでのコレクションの更新処理では書いていませんでした）、これは Table 関数で囲わないと"戻り値の型が合わない"とエラーが出たために追記した処理です。もちろん、使用しない戻り値の型を変換しているだけですので、処理結果は変わりません。
　ここの Patch 関数の戻り値はレコードで、UpdateIf 関数の戻り値はテーブルになるので、どうやらForAll 関数内の処理において、If 分岐によって戻り値が異なるのは NG なのかもしれません。この辺り、調べてもよく分かりませんでしたので、ご存知の方がいたら是非教えてください！
<br>
　ということで、保存を Collection 経由に変更する作業は完了です。
　こんな感じで動きます。ドロップダウンを変更した時点ではコレクションのみ更新され、保存ボタンをクリックした時点で SharePoint リストが更新されることがお分かりいただけるかと思います。
![Collection完成.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/4b5f81b9-1f0c-0165-627d-c384b8b95243.gif)


## 各勤務者から申請された希望勤務を表示する
　ドロップダウンの下に各勤務者から申請された希望勤務を表示させます。
　事前に、SharePoint リストに希望勤務パターンのみを格納したデータを登録しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/d8204eaa-bafe-98c3-90fd-374bc948610d.png)

　ドロップダウンの高さを縮めてその下にラベル LabelRequestWorkPattern を追加し、Text に以下を記載します。該当の日付・勤務者の希望勤務パターン列の値を抽出しているだけです。

```:LabelRequestWorkPattern-Text
First(Filter(ShiftData, mWorkDateValue=Value(LabelDayValue.Text), mWorkUser.DisplayName=ThisItem.uWorkUser.DisplayName)).mRequestWorkPattern
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/eda44397-65ef-3152-6f68-65a755daf65c.png)

　これで、各勤務者から申請された希望勤務を表示する作業は完了です。ここは簡単ですね。
　もちろん、希望勤務に対して勤務パターンを設定すると、同じレコードに勤務パターンが書き込まれます。
![希望勤務表示完成.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/c0ca2fec-01b0-d2f8-54c8-88e408bc8f71.gif)


## 勤務パターンを色付けする
　勤務シフト_パターンのリストに色情報を格納していますので、その情報を抽出します。
　方法論は、こちらをご参照ください。
　[Power Apps で色の設定情報を読み書きする簡単な方法](https://qiita.com/KodamaJn/items/1bc02fb23a889597c7e4)

　まずは、いちいち SharePoint リストから値を抽出するのは無駄なアクセスなので、App の OnStart で勤務シフト_パターンのリストからコレクション PatternData に値を格納しておきます。

```:OnStart(追記分のみ)
ClearCollect(PatternData, 勤務シフト_パターン);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/1187b3b1-f9d8-35d2-0b7b-ab9c3cfa1f1f.png)
　追記したら、OnStart を実行しておきましょう。

　続いて、ドロップダウンの Fill を以下に書き換えます。
　ドロップダウンで何かしら選択している場合に、該当する勤務パターンの色設定情報を先ほどのコレクション PatternData から RGBA 毎に抽出しているだけです。未選択の場合に White にしている理由は、これを指定しないと未選択の場合に背景が透明になってしまい、見にくいためです。

```:Fill
If(IsBlank(DropdownWorkPattern.Selected),
    White,
    RGBA(
        LookUp(PatternData, pWorkPattern=DropdownWorkPattern.Selected.pWorkPattern).pRed, 
        LookUp(PatternData, pWorkPattern=DropdownWorkPattern.Selected.pWorkPattern).pGreen, 
        LookUp(PatternData, pWorkPattern=DropdownWorkPattern.Selected.pWorkPattern).pBlue, 
        LookUp(PatternData, pWorkPattern=DropdownWorkPattern.Selected.pWorkPattern).pAlpha
    )
)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/db4d44d1-139e-b362-4230-2a576dff8c76.png)


ついで、文字を見えやすくするため、文字の色は選択時は White、未選択時は Black にしています（処理の説明は割愛）。

　ついでに、希望勤務パターンも色付けしてみました。こちらは文字色と枠を。先ほどのコレクション PatternData から、ラベルで表示されている勤務パターンの色を RGBA 毎に抽出しているだけです。


```:Color/BorderColor
RGBA(
    LookUp(PatternData, pWorkPattern=LabelRequestWorkPattern.Text).pRed, 
    LookUp(PatternData, pWorkPattern=LabelRequestWorkPattern.Text).pGreen, 
    LookUp(PatternData, pWorkPattern=LabelRequestWorkPattern.Text).pBlue, 
    LookUp(PatternData, pWorkPattern=LabelRequestWorkPattern.Text).pAlpha
)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405544/2394cefe-ea0b-1646-d074-f8926458a1ac.png)

　これで、勤務パターンを色付けする作業は完了です。ここも簡単ですね。


# おわりに
　ここまでで、勤務希望の閲覧から勤務シフト作成までできるようになりました。
　その４では、作成した勤務シフトを各勤務者の予定表に追加する機能と、そもそもの部分である各勤務者が希望勤務を申請できる別アプリを実装します。

　その４はこちら：https://qiita.com/KodamaJn/items/2765f395d807de13f785