業務改善と標準化を同時に実現:MS 365業務システム開発

【Power Apps】 ギャラリー内の複数行を一括保存する、ForAll+Patchと超高速なコレクション+Patchのやり方

  
【Power Apps】 ギャラリー内の複数行を一括保存する、ForAll+Patchと超高速なコレクション+Patchのやり方
\ この記事を共有 /
【Power Apps】 ギャラリー内の複数行を一括保存する、ForAl...

一般的なPowerAppsで複数行を一括保存ができるForAllとPatch関数を使うやり方と更に高速で一括保存ができるコレクションとPatch関数を使う方法を説明しています。更に、データの追加、削除機能の作り方も学べます。

(動画時間:11:07)

Udemy.comでオンラインコースを運営しています。
マイクロソフトPowerApps 中級編【SharePointで、実務で使える業務アプリの作り方:勤怠管理アプリ編】
⇒ 半額になる「ディスカウントリンクページ」へ


一括保存のやり方は「ForAll+Patch」と「コレクション+Patch」のやり方がある。

こんにちは、リーンシグマ、ブラックベルトのマイク根上です。
業務改善コンサルをしています。

前回の動画でPowerAppsのギャラリーコントロール内で
直接編集ができるやり方をやりました。
⇒「【Power Apps】ギャラリー内での編集機能の作り方(DisplayMode、Visible、Reset属性の使い方)」

それは一行ずつ変更して保存するやり方でしたが、
変更データ数が多いとユーザーの変更作業に時間が掛かり、
場合によってはあまり良くありません。

そこで今日は同じ様にギャラリー上で変更をするのですが、
最後に一回のクリックで全てのデータを
一括保存するやり方をご紹介します。

これで更なるユーザー体験を上げる事ができるのです。

それをするのに通常はForAll関数にPatch関数を入れ子にして行います。
そのやり方をまずご紹介して、その後に
もっと高速にできるコレクションとPatch関数でやる
上級者向けのやり方もお見せしますのでご期待下さい。

それでは最初に完成形を見てみましょう。

ギャラリー内での新規入力/削除機能、一括編集機能の完成形を見る。

上図の画面右上の鉛筆アイコンが編集ボタンです。
前回の方法だと各行にそのボタンがあったので、
今回はボタンが一つだけなので画面が見易いですね。
それをクリックして全ての行が編集モードになります。

また、編集ボタンの右の「+」アイコンがデータ追加ボタンです。
それをクリックすると、一番上の行に空欄の行が挿入されて
ユーザーが新規のデータを入力できる様になります。(下図参照)
次に話します保存ボタンで一緒に一括保存されます。

上図は編集モードで、各行のテキスト入力コントロール内の値を変更して、
右上の「ForAll+Patch」の保存ボタンを押すと
SharePointリストに一括保存ができます。

また、編集モード中に、各行にごみ箱アイコンが表示されます。
それが削除ボタンで、それをクリックすると
その行が直ぐにギャラリーとデータソースから削除されます。

これでデータの追加、変更、削除という業務システムで必須の機能の実装ができる様になります。
それではこの作り方を見てみましょう。

ForAllとPatch関数を使ったギャラリーの一括保存機能の作り方

一括編集モードの作り方

ギャラリー部分は前回作ったギャラリーと一緒です。
ギャラリーの作り方や使い勝手の良いボタンの作り方は
前回の記事を次のリンクからご覧下さい。
⇒「【Power Apps】ギャラリー内での編集機能の作り方(DisplayMode、Visible、Reset属性の使い方)」

まずは鉛筆アイコンの編集ボタンの「OnSelect」属性で、
ボタンが押されたらUpdateContext関数で
変数:「編集Vis」に「true」が入いります。

編集ボタンの「OnSelect」属性
=UpdateContext({編集Vis:true})

すると全てのテキスト入力コントロールが編集モードになります。
それは各テキスト入力の「DisplayMode」属性に、
変数:「編集Vis」にtrueが入ったら編集モードに、
そうじゃなかったら閲覧モードにすると言う式が入っているからです。

全テキスト入力コントロールの「DisplayMode」属性
=If(編集Vis, DisplayMode.Edit, DisplayMode.View)

この編集モードで、ごみ箱アイコンが出てきました。
それはその「Visible」属性に、変数:「編集Vis」が入っているからです。

削除ボタンの「Visible」属性
=編集Vis

ギャラリー内のレコードの削除機能の作り方

そのごみ箱の削除機能を見てみましょう。
その「OnSelect」属性に、Remove関数で
ギャラリーと同じデータソース名を入れ、
そして「ThisItem」つまり、選択されたレコードを削除する
という式を入れるだけです。

削除ボタンの「OnSelect」属性
=Remove(Tbl_顧客リスト,ThisItem)

ThisItemはレコード型の演算子で、
ギャラリーやデータテーブルコントロール内で
ユーザーが選択したレコードを指定したり、
ピリオドの後に列名を入れて列を指定できる便利な演算子です。

ギャラリーへの新規データの追加機能の作り方

次に新規データの追加機能を見てみましょう。
追加ボタンの「OnSelect」属性で、
Patch関数の珍しい使い方がされています。

追加ボタンの「OnSelect」属性
=Patch(
   Tbl_顧客リスト,
   {ID: Blank()}
);
UpdateContext({編集Vis:true})

まず、変更するデータソースを指定して、
第二引数でSharePointリストのID列にBlank関数で空白を入れています。
通常この後、第三引数で列名と、代入する値を指定しますが、
それを省略して、この様に書くと
データなしでレコードを一つ追加します。

そしてその後にUpdateContext関数で編集モードに切り替えます。
それをクリックすると、編集モードで
新規のデータを入力する準備がされるのです。

もう一つ重要な事はこのギャラリーの「Items」属性で、
どこかの列で昇順で並べ替えをしておく事です。

空白は最初に来るので新規入力の行が
必ず一番上に来るようになります。
これでユーザーは直ぐに新規データの入力ができるのです。

ギャラリーの「Items」属性
=SortByColumns( Tbl_顧客リスト, “Customer”, Ascending)

ForAllとPatch関数での一括保存機能の作り方

そして最後に保存ボタンの「OnSelect」属性を見てみましょう。

保存ボタンの「OnSelect」属性
=ForAll(
   Gallery1.AllItems,
   Patch(
      Tbl_顧客リスト,
      ThisRecord,
      {
         Customer: TI_Customer1.Text,
         Contact: TI_Contact1.Text,
         Email: TI_Email1.Text
      }
   )
);
UpdateContext({編集Vis: false})

最初のForAll関数でこのギャラリーの
全レコードを一つずつ操作します。

そしてその中のPatch関数で変更先のデータソース名、
そして「ThisRecord」演算子を入れています。
ギャラリーのデータソースがこのPatch関数の
変更対象のデータソースなのでこの演算子が使え、
正しく変更先をキャッチできるのです。

そして第三引数で、変更する各列に
テキスト入力での入力内容を入れています。

これでデータを変更して、保存ボタンを押し、
一括保存ができるのですが、画面が少しちらついてしまいます。

これはForAllで行を一つずつ保存するので
その都度クラウドのデータソースまでインターネットを行き来して、
その時間差があるので画面がちらつくのです。

ForAll+Patchの一括保存の問題点

このForAll+Patch関数のやり方で一括保存ができ、
多くの人がこれを使っていますが、
この方法にはさっきのちらつく問題以外にも大きな問題があります。
特に対象のデータが多くなるに連れてそれが顕著になるのです。

その問題の一つが、データ数に比例して処理時間が長くなる事です。
また、変更をしていない行も上書き保存をするので
それは本当に無駄な処理です。

もう一つの問題は確率は少ないですが、
タイミングによっては他のユーザーが変更したデータを
元のデータに戻してしまう可能性があります。

そこで上級者向けですが、これらの問題を解決する方法を次にお見せします。

コレクション+Patchの超高速一括保存機能の作り方

このやり方の基本的な考え方は、
各行内のコントロールのどれかが変更されたら
その変更後の全列の値をコレクションに保存し、
一括保存ボタンが押されたら、
コレクションのデータだけデータソースに保存するのです。
更にForAllを使わずPatch関数だけでこれを行います。

変更結果の行のデータをコレクションに保存する仕組みを作る。

まず、このスクリーンの「OnVisible」属性に、
ClearCollect関数で対象のデータソース全体をコレクションに入れます。
そしてその直後にClear関数で全てのデータを削除します。
これは毎回このスクリーンに来た時に
対象データソースと同じ列名で、
データの無いコレクションを作りたいからです。

スクリーンの「OnVisible」属性
=ClearCollect(コレクション, Tbl_顧客リスト);
 Clear(コレクション);

次に各テキスト入力の「OnChange」属性に、次の数式を入れます。

各テキスト入力の「OnChange」属性
=If(
   CountIf(
      コレクション,
      ID = ThisItem.ID
   ) = 0,
   Collect(
      コレクション,
      ThisItem
   )
);
Patch(
   コレクション,
   LookUp(
      コレクション,
      ID = ThisItem.ID
   ),
   {Customer: Self.Text}
)

これによってユーザーの各テキスト入力への
入力内容が変わる度に、この式が実行され、
If関数内のCountIf関数でさっき作ったコレクションに
変更された行の内容がすでに記録されているかを判断して、
記録されていなければデータソースの
その行だけの全列の値をそのコレクションに記録します。

もしすでに記録されていれば何もしません。

そして次のPatch関数で変更している列の変更内容を
そのコレクション内のその行のその列に上書きします。

数式内の「Self」演算子は便利で、
この属性のコントロールを相対的に指定するのです。
これはコントロール名を直接書くのと違って、
記述が短いし、この式を他のコントロールにコピペしても、
相対的に各コントロールを参照できるのです。

そこで、この式を他のテキスト入力の「OnChange」属性にコピペして、
変更先の列名だけを変えて使えます。

これで、各テキスト入力で値を変更したい行だけ、
その変更結果をコレクションに保存できるのです。

コレクションに保存されたデータをデータソースに一括保存する。

そして最後に新たな保存ボタンを作ります。
さっきの保存ボタンをコピペして使うと作業が速いです。
その「OnSelect」属性に次の式を入れます。

新たな保存ボタンの「OnSelect」属性
=Patch(
   Tbl_顧客リスト,
   ShowColumns(
      コレクション,
      ”ID”,
      ”Customer”,
      ”Contact”
   )
);
Clear(コレクション);
UpdateContext({編集Vis: false})

ここではPatch関数の引数は二つだけで、
第二引数にテーブル型のデータを入れると、
そのテーブルのデータを全て第一引数のデータソースに入れれるのです。

更にそのテーブルにプライマリーキーの
「ID」列(SharePointリストの場合)が入っていれば、
既存データの更新ができるのです。
今回のコレクションにはその「ID」が含まれます。

今回の場合ですと、コレクションの中には
変更の必要の無い列が沢山含まれています。
そこでShowColumns関数で変更の必要のある列だけに絞ります。
これで処理速度が上がるし、無駄なエラーの回避にもなります。

ここで「ID」列を必ず入れて下さい。無いと機能しません。
これで一括保存ができるのです。

次にClear関数でそのコレクションを空にして、
次の変更/一括保存の準備をします。

そしてその後の式で編集モードから閲覧モードに移行にします。

この方法だと一括保存ボタンを押した後のちらつきがなく、一瞬で一括保存します。
また新規機能も全く問題なく機能しますし、
変更した行だけ上書き保存するから高速だし、
他のユーザーとの問題も無しで一括保存ができるのです。

今回の内容は新規入力、データ編集/削除機能を持った
データの一覧画面を作る最良の方法だと思います。

「こちらの記事も読まれてます。」