1. 記事一覧 >
  2. ブログ記事
Power Apps
category logo

Power Appsのギャラリーでエクセル風 編集可能なグリッドテーブルを作成 2/2

(更新) (公開)

はじめに

前回記事「Power Appsのギャラリーでエクセル風 編集可能なグリッドテーブルを作成 1/2」の続きです。
今回は、行の追加、行の削除を可能にして、完成させます。


全動作内容 動画


行の追加ボタン作成

前回記事で編集機能が実装できたので、行の追加機能を追加します。


編集ボタンの横に新規追加ボタンを置きます。
ここで、新規追加ボタンは編集ボタンの位置へ配置し、編集ボタンは、右にずらします。
アイコンは、「追加」で検索します。
アイコンとラベルは、ico_Newlbl_New と名付けます。


ico_New

Width
40
Height
40
Visible
loc_GalleryMode=Blank()

lbl_New

Text
"新規追加"
FontWeight
FontWeight.Bold
Height
40
X
ico_New.X + ico_New.Width
Y
ico_New.Y
Visible
ico_New.Visible

ico_Edit

X
lbl_New.X + lbl_New.Width + 30
Y
ico_New.Y

lbl_Edit

X
ico_Edit.X + ico_Edit.Width
Y
ico_New.Y

ico_Save

X
ico_New.X
Y
ico_New.Y

lbl_Save

X
ico_Save.X + ico_Save.Width
Y
ico_New.Y

行の追加ボタン実装

行の追加ボタンをクリックしたら、行の追加モードになるようにします。


OnSelect で コレクション col_Updates空のレコード2件とします。


ico_New

OnSelect
ClearCollect(col_Updates, {ID:1},{ID:2});
UpdateContext({loc_GalleryMode: "New"});

ClearCollect(col_Updates, {ID:1},{ID:2}); は、ID のみ存在する空のレコード2件です。
loc_GalleryMode は、"Edit" だけでしたが、行の追加モード "New" を導入します。


lbl_New

OnSelect
Select(ico_New)

これだけの場合、見た目は、何も起きません。 行の追加モードの場合、ギャラリーの表示を loc_GalleryMode と連動させます。


gal_EditableTable

Items
If(loc_GalleryMode="New", col_Updates,'Members')

loc_GalleryMode="New" のとき、ギャラリーのデータソースを col_Updates にするという意味になります。
loc_GalleryMode="New" 以外の時のデータソースは、SharePoint の Members リストです。
ギャラリーの Items プロパティは、データソースを意味します。


次に、txt_MemberIDtxt_Nametxt_Age について、行の追加モードの時でも編集可能にします。


txt_MemberIDtxt_Nametxt_Age

DisplayMode
If(loc_GalleryMode in ["New", "Edit"], DisplayMode.Edit,DisplayMode.View)

loc_GalleryMode in ["New", "Edit"] は、loc_GalleryMode = "New" Or loc_GalleryMode = "Edit" と同じ意味です。loc_GalleryMode を2回書くのを避ける書き方になります。


このままでは、2行までしか追加できませんので、2行目を変更したら、3行目が出現するようにします。


txt_MemberIDtxt_Nametxt_Age

OnChange
With(//With関数。この()内だけで使える変数を定義。
    {wLastID: Last(col_Updates).ID},//With()内だけで使える変数。wLastID=col_Updatesの最後のレコードのID
    If(loc_GalleryMode="New" And ThisItem.ID=wLastID, Collect(col_Updates, {ID: wLastID+1}))
    //loc_GalleryMode="New"かつ最後の行が編集されたとき、col_Updatesに最後のID+1のレコードを追加
);

With( レコード、数式 )With() 内だけで使える変数 wLastID を定義しています。
wLastID は、col_Updates の最後のレコードの ID です。(1,2,3... の連番の一番大きい値)
If(loc_GalleryMode=... 部分は、数式で、loc_GalleryMode="New" かつ最後の行が編集されたとき、col_Updates{ID: 最後のID+1} のレコードを追加しています。
ThisItem.ID は、ギャラリーの現在行の ID、Collect は、レコードの追加関数です。(ClearCollect の場合は、追加ではなく、最初から作り直しです。)
col_Updates にレコードを追加して、なぜ、ギャラリーの空行が増えるかというと、New モードの時は、ギャラリーのデータソースが col_Updates だからです。
垂直ギャラリーの表示行数は、データソースのレコード数と連動する性質ですので、col_Updates の行が増えれば、ギャラリーの表示行も増えます。

OnChange は、入力中ではなく、内容が確定したときに発動します。(エンターキーを押したり、他へフォーカスが移った時です。)

OnChange 空行追加 図


OnChange 空行追加 動画

まだこの段階では、見た目だけ追加できるようになって、実際に、データソースの SharePoint の Members リストに追加できるわけではありません。
次で実際に追加できる機能を実装します。


行の追加機能実装

編集の時に表示していた保存、キャンセルアイコンを New モードのときでも表示するようにします。


ico_Save

Visible
loc_GalleryMode in ["New", "Edit"]

保存ボタンの  OnSelect  の動作を New モード、Edit モードのときで分けます。


ico_Save

OnSelect
//Newモード、Editモードでcol_Updatesへの扱いを変える
If(
    //Newモードの場合
    loc_GalleryMode="New",

    //追加箇所の記録
    ForAll(//ForAll一番目の引数=テーブル構造のデータ
        gal_EditableTable.AllItems As NewRows,//ギャラリー内の全てのレコードが対象。NewRows として定義
        Patch(col_Updates,
        LookUp(col_Updates, ID=NewRows.ID), {//LookUp(col_Updates, ID=NewRows.ID)は、ID以外何も入っていないレコード(New画面を開いたときとOnChangeでIDだけ入れている。)
            MemberID: NewRows.txt_MemberID.Text,//該当ID行の入力内容
            Name: NewRows.txt_Name.Text,
            Age: Value(NewRows.txt_Age.Text)
        })
    );

    UpdateIf(col_Updates, true, {ID: Blank()});//ID列を消去。trueは、全レコードという意味。
    //Remove(col_Updates, Last(col_Updates))//最後のレコードは、必ず空白行のため、削除。
    RemoveIf(col_Updates, IsBlank(MemberID) And IsBlank(Name) And IsBlank(Age))//空白行、削除。
    //実は問題有り:New モードに切り替えた時、最初の状態で2行空行があり、そのまま保存ボタンを押すと、1行空レコードが残る。
    //他にも、一度入力して、全部消した行も追加対象になる。
    //→RemoveIfで空行を捉えて、消す仕様とする。
    ,
    //Editモードの場合
    loc_GalleryMode="Edit",

    //ここは、編集のときの内容と同じ
    ForAll(
        Filter(
                gal_EditableTable.AllItems,
                tog_isChanged.Value
        ) As ChangedRows,
        Patch(col_Updates,
        Defaults(col_Updates), {
            ID: ChangedRows.ID,
            MemberID: ChangedRows.txt_MemberID.Text,
            Name: ChangedRows.txt_Name.Text,
            Age: Value(ChangedRows.txt_Age.Text)
        })
    )
);

// SharePointのMembersリストをcol_Updatesを使って書き換え
// (Membersリスト隠し列のIDとcol_UpdatesのIDの値が一致した行が書き換わる。col_UpdatesのIDが空白の場合、行追加。)
Patch(Members, col_Updates);
Clear(col_Updates);//編集追加箇所の記録をクリア

// Viewモードに戻す。
UpdateContext({loc_GalleryMode: Blank()});

参考元記事https://www.matthewdevaney.com/power-apps-excel-style-editable-table-part-2)の方は、
Remove(col_Updates, Last(col_Updates))
になっていたのですが、一度入力したところの入力内容を消してそのまま登録すると、空行が登録されるため、
RemoveIf(col_Updates, IsBlank(MemberID) And IsBlank(Name) And IsBlank(Age))
として、空行は登録対象にしないようにしました。


以下のイメージで追加されます。

空行は登録対象にしない 行追加 図


空行は登録対象にしない 行追加 動画


キャンセルボタンは、編集の時と同じコードで問題なく、変更無しです。


ico_EditCancel

OnSelect
// テキスト入力をリセットして、Defaultの値に戻す。
// Defaultの値とは、データソース(SharePointのMembersリスト)の値のこと。
//txt_MemberID、txt_Name、txt_Age 各々の Reset プロパティを
//loc_ResetTextInputs とするため、これでリセットの意味になる。
UpdateContext({loc_ResetTextInputs: true});
UpdateContext({loc_ResetTextInputs: false});

//編集箇所の記録をクリア
Clear(col_Updates);

// Viewモードに戻す。
UpdateContext({loc_GalleryMode: Blank()});

行の削除ボタン作成

変更機能が実装できたので、行の追加機能を追加します。


編集ボタンの右側に削除ボタンを置きます。
アイコンは、「ごみ箱」で検索します。(注意:「ゴミ箱」ではないです。)
アイコンとラベルは、ico_Deletelbl_Delete と名付けます。
loc_GalleryMode に "Edit", "New" に加えて、"Delete" を設けます。


ico_Delete

Width
40
Height
40
X
lbl_Edit.X + lbl_Edit.Width + 30
Y
ico_New.Y
OnSelect
UpdateContext({loc_GalleryMode: "Delete"});
UpdateContext({loc_IsDeleteMode: true});
Visible
loc_GalleryMode=Blank()

lbl_Delete

Text
"削除"
FontWeight
FontWeight.Bold
Height
40
X
ico_Delete.X + ico_Delete.Width
Y
ico_New.Y
Visible
ico_Delete.Visible
OnSelect
Select(ico_Delete)

削除ボタンを押したときに出現するボタンを設置します。


削除ボタンを押したときに出現するボタンは、以下の3種類です。
・削除確定ボタン: 押したら、削除対象に指定した行が消えます。
・削除キャンセルボタン: 押したら、削除操作が取りやめになります。
・削除行選択ボタン: 削除アイコンが各行に配置されます。押したら、削除対象行として選択されます。


各々、以下のように命名します。
・削除確定ボタン: ico_ConfirmDelete(「チェック」アイコン)、lbl_ConfirmDelete
・削除キャンセルボタン: ico_CancelDelete(「キャンセル」アイコン)、lbl_CancelDelete
・削除行選択ボタン: ico_DeleteLine(「ごみ箱」アイコン)


各々、配置します。(とりあえず、配置のみです。)
削除行選択ボタンは、ギャラリー内に配置します。手動でドラッグして、行の右側に持ってきます。


ico_ConfirmDelete

Width
40
Height
40
X
ico_New.X
Y
ico_New.Y

lbl_ConfirmDelete

Text
"削除確定"
Height
40
FontWeight
FontWeight.Bold
X
lbl_New.X
Y
ico_New.Y
OnSelect
Select(ico_ConfirmDelete)
Visible
ico_ConfirmDelete.Visible

ico_CancelDelete

Width
40
Height
40
X
ico_Edit.X
Y
ico_Edit.Y

lbl_CancelDelete

Text
"削除キャンセル"
Height
40
FontWeight
FontWeight.Bold
X
lbl_Edit.X
Y
ico_New.Y
OnSelect
Select(ico_CancelDelete)
Visible
ico_CancelDelete.Visible

配置が終わったら、このような状態になります。
重なっていますが、この後 Visible を調整して対処します。

削除ボタンを押したときに出現するボタン配置が終わった状態


フラグまとめ

行の削除機能実装前に、何をやっているのか分かりにくくなりますので、行の削除機能で新たに登場するフラグを交えて、先にまとめを載せます。


✔:表示 ❌:非表示
新規追加1:新規追加ボタンクリック直後
新規追加2:新規追加画面で、ごみ箱アイコンをクリック直後
編集1:編集ボタンクリック直後
編集2:編集画面で、ごみ箱アイコンをクリック直後
削除:削除ボタンをクリック直後

View新規追加1新規追加2編集1編集 2削除
loc_GalleryModeBlank()"New""New""Edit""Edit""Delete"
loc_IsDeleteModefalsefalsetruefalsetruetrue
新規追加ボタン
編集ボタン
削除ボタン
右側のごみ箱アイコン
保存ボタン
キャンセルボタン
削除確定ボタン
削除キャンセルボタン

行の削除機能実装

ico_DeleteLine について、クリックされたら、col_DeleteRecords コレクションにクリックされた行のデータを格納するようにします。


ico_DeleteLine

OnSelect
If(Self.Icon=Icon.Trash, Collect(col_DeleteRecords, ThisItem), Remove(col_DeleteRecords, ThisItem));
If(CountRows(col_DeleteRecords)>0 Or loc_GalleryMode="Delete", UpdateContext({loc_IsDeleteMode: true}), UpdateContext({loc_IsDeleteMode: false}))

ThisItem は、ギャラリーの現在の行を意味します。
クリックされたアイコンがごみ箱アイコン:col_DeleteRecords に現在行データを追加
クリックされたアイコンがキャンセルアイコン:col_DeleteRecords から現在行データを削除
としています。
If(CountRows(... のところは、削除対象が1件以上あったり、Delete モードのとき、loc_IsDeleteModetrue に切り替えています。
この時点では、loc_GalleryMode="Delete" だけで削除モードだと分かるのですが、この後、編集モード、行追加モードでも削除機能を有効にするため、別の変数 loc_IsDeleteMode で現在削除操作中なのかを判定しています。


さらに、ico_DeleteLine について、クリックされたら、キャンセルアイコン(× 型のアイコン)になるようにします。
キャンセルアイコンは、コードでアイコンを書き換えています。


ico_DeleteLine

Icon
If(ThisItem in col_DeleteRecords, Icon.Cancel, Icon.Trash)

現在行が col_DeleteRecords に含まれていない場合、ごみ箱アイコン、含まれている場合、キャンセルアイコンを設定しています。


現在行が col_DeleteRecords に含まれている場合、削除対象行なのですが、アイコンの形状以外に削除対象として選択された行が分かりやすくなるように、テキスト入力の色を変えます。


txt_MemberIDtxt_Nametxt_Age

Fill
If(ico_DeleteLine.Icon=Icon.Trash, Color.White, RGBA(238, 204, 204, 1))

RGBA(238, 204, 204, 1) は赤っぽい色です。


削除対象行を選択した状態


ico_DeleteLine の表示非表示を調整します。


ico_DeleteLine

Visible
loc_GalleryMode in ["Delete","Edit"] Or (loc_GalleryMode="New" And ThisItem.ID<Max(col_Updates,ID) And CountRows(col_Updates)>1)

編集、削除画面のときは、無条件で表示、新規追加画面のときは、一番下の空白行以外(ThisItem.ID<Max(colUpdates,ID))かつ空白行含め2行以上あるときに表示としています。


ico_ConfirmDeleteico_CancelDelete の表示非表示は、表示モード(loc_GalleryMode)ではなく、loc_IsDeleteMode で切り替えます。


ico_ConfirmDeleteico_CancelDelete

Visible
loc_IsDeleteMode

新規追加と編集の時に表示される 保存ボタンとキャンセルボタンの表示について、削除操作中は非表示にします。


ico_Save

Visible
loc_GalleryMode in ["New", "Edit"] And !loc_IsDeleteMode

!true, false の反転です。


削除確定ボタンを押したときに、削除対象レコードをデータソース(SharePoint Members リスト)または、col_Updates(追加中レコード)から削除するようにします。


ico_ConfirmDelete

OnSelect
//削除対象レコードをデータソース(SharePoint Membersリスト)から削除
If(
    loc_GalleryMode in ["Delete", "Edit"],
    Remove('Members', col_DeleteRecords)//削除、編集モードの時は、こちらが実行されて、直接削除
    ,
    Remove(col_Updates, col_DeleteRecords)//新規追加モードの時は、こちらが実行されて、col_Updates(追加中レコード)から削除
);

Clear(col_DeleteRecords);//削除対象レコードをクリア
UpdateContext({loc_IsDeleteMode: false});//削除操作中解除
If(loc_GalleryMode="Delete", UpdateContext({loc_GalleryMode: Blank()}));//削除モードの時は、Viewモードに戻す。

編集モードのとき、保存ボタンを押さなくても、削除確定ボタンを押したときにデータソース( SharePoint Members リスト)から削除されます。


削除キャンセルボタンを押したときに、削除操作中状態を解除します。


ico_CancelDelete

OnSelect
Clear(col_DeleteRecords);//削除対象レコードをクリア
UpdateContext({loc_IsDeleteMode: false});//削除操作中解除
If(loc_GalleryMode="Delete", UpdateContext({loc_GalleryMode: Blank()}));//削除モードの時は、Viewモードに戻す。

最後に、今のモードが View なのか、新規追加なのか、編集なのか、削除なのか、分かりにくくなっていますので、ラベルで表示するようにします。
lbl_CurrentMode を追加します。

「モード」と表示されてもユーザーには分からないと思いますので、デバッグ表示的なつもりです。


lbl_CurrentMode

Text
$"モード:{
Switch(loc_GalleryMode ,
      "New", "新規追加",
      "Edit", "編集",
      "Delete", "削除",
      "View"
)
}"

$"文字列{数式}" の書き方です。"文字列" & 数式 と同じ意味です。どちらの書き方でも、数式は、文字列を返さないといけません。


「モード」表示


動作確認/動作例

新規追加

メンバーID名前年齢
0012Harper Khan21

を追加すると見せかけて、やめる。

保存ボタンを押して、

メンバーID名前年齢
0030Mason Hernandez22

追加

編集

メンバーID名前年齢
0012Sophia Patel29

削除

メンバーID名前年齢
0005Oliver Davis37

メンバーID名前年齢
0005Harper Khan21

に変更して、保存

削除

メンバーID名前年齢
0001Jackson Parker37
0003Emily Foster27

を選択して、削除確定


全動作内容 動画


できました!

loading...