OutSystemsで結構聞く要望として、テーブル上でデータ編集したいというものがある。DataGridなら簡単に実現できそうなので手順をメモ。
DataGridコンポーネントも、Traditionalの頃に比べてだいぶ良くなっている。これなら使用を検討してもよいかと思う。
環境情報
Personal Environment(Version 11.18.1 (Build 37884))
Service Studio(Version 11.53.43)
OutSystems Data Grid(Version 2.10.1)
サンプル
Forgeコンポーネント: HousesoftSampleReactiveのV1.0.16。
DataGridFlow > DataGridTableEdit Screen
テストデータ
以下の構造のEntityを表形式で表示・編集するサンプル画面を作っていく。
NameとDescriptionがText型、PriceとStockがInteger型。
Gridに表示
参照
以下のように、OutSystemsDataGridから必要な要素を参照する。
データの取得
Data Gridに表示するデータは、AggregateではなくData Actionで取得する。
これは、List型をJSON形式に変換したデータが必要であるため。
- ArrangeData Action: JSONに変換するOutSystemsDataGrid/APIにあるAction。Object型を受け取るため、「ToObject(AggregateのList)」のように渡す
- Assign: ArrangeData.DataJSONを出力変数に編集
ArrangeData Actionの代わりにJSONSerializeでJSON化すると、以下のエラーが表示され、データがGridに表示されない。
You cannot use JSONSerialize and make the grid editable. Please use ArrangeData action for this scenario.
UI
OutSystemsDataGrid/Structures/Gridを画面に配置する。
以下のプロパティを設定。
- Name: Widgetの名前。画面内のロジックでGridに対して操作するときに、「どのGridか」を表すために設定しておく必要がある
- Data: DataActionの出力(データのJSON)
- IsDataFetched: DataActionのIsDataFetched (データの取得が終わってクライアントに渡っているかを示すDataAction/Aggregateのプロパティ)
- OptionalConfigs.AllowColumnEdit: True(Grid上でのデータ入力を許可する設定)
表示する列を手動で設定
実はここまでの設定で、渡したデータから自動的に表示するべき列を特定してくれるので、Grid自体は表示可能。
ただ余計な列を表示してしまったり、Date型の表示がうまくいかなかったりしたので、表示する列を明示的に設定しておく。
配置したGridのGridColumnsPlaceholder内に、OutSystemsDataGrid/Columnsにある列の種類に対応した**Columnという名前のWidgetを、表示したい列分だけ配置する。
最低限必要なプロパティは
- Header: 列の先頭に表示するテキスト
- Binding: JSONデータ内での該当列の位置。「Entity名.属性名」を指定
編集させたくないId列については、ColumnOptionalConfigs.AllowEditをFalseにしておく。
なお、今回は数値型(PriceとStock)がInteger型なので設定がいらないが、デフォルトでは小数点以下が入力できない。
NumberOptionalConfigs.DecimalPlacesを1以上に設定すれば、小数点以下を入力できるようだ。
Gridで編集
追加・更新・削除は、クライアント側のGridで発生する。
一定のタイミングでこの修正内容をGridから取り出し、サーバーに送信。サーバー側ではServer Actionで通常通りEntityに書き込めばよい。
Context Menuを整理しておく
DataGrid内に表示するContext Menu (右クリックメニュー) は、画面に配置したGridのContextMenuPlaceholderにあるContextMenu Widgetによって定義する。
Context MenuのMenuItems Placholderに、OutSystemsDataGrid/ContextMenuにあるMenuItem_で始まるWidgetを配置すると対応するメニューがContextMenuに表示される。
デフォルトでいくつか配置されているが、以下で編集用メニューを表示するときに邪魔なので、あらかじめContextMenu/MenuItem_Copy_WithHeaders (選択中のセルをヘッダ付きでクリップボードにコピーする機能)以外を削除しておく。
追加
Context Menuを利用する
Grid > ContextMenuPlaceholder > ContextMenu Block > MenuItems Placeholderに、OutSystemsDataGrid/ContextMenu/MenuItem_Rows_Addを配置することで、Context Menuに「Add Row(s)」というメニューが追加される。
クリックすると、選択中の行の上に空行を追加する。
Actionを利用する
画面内にButtonを配置し、そのScreen ActionでOutSystemsDataGrid/API_Rows/AddNewRows Action (Client Action)を呼ぶ。
GridWidgetIdには「<Grid名>.Id」を設定する。追加する行数を指定するNumberOfRowsはデフォルトが1なので、何も設定しなくてもよい。
更新
更新については、GridのAllowColumnEditをTrueにしておくだけでよい。
削除
Context Menuを利用する
Grid > ContextMenuPlaceholder > ContextMenu Block > MenuItems Placeholderに、OutSystemsDataGrid/ContextMenu/MenuItem_Rows_Deleteを配置することで、Context Menuに「Delete Row(s)」というメニューが追加される。
クリックすると、選択中の行を削除する。
Actionを利用する
画面内にButtonを配置し、そのScreen ActionでOutSystemsDataGrid/API_Rows/RemoveSelectedRows Action (Client Action)を呼ぶ。
GridWidgetIdには「<Grid名>.Id」を設定する。
更新の反映
ここまでの作業では、修正はあくまでもクライアント側(Grid内)にとどまっている。
そこで、
- Gridから変更点を抽出する(OutSystemsDataGrid/API_Data/GetChangedLines Action)
- 変更点はJSON形式で、GetChangedLinesのOutput Parameterに設定されている。JSONDeserialize要素を使い、List型に戻す
- 追加データ→ChangedLines.AddedLines
- 更新データ→ChangedLines.EditedLines
- 削除データ→ChangedLines.RemovedLines
- Server Actionnに2でデシリアライズしたデータを渡し、通常のデータ更新のように処理する
- Refresh Data要素でデータ取得したData Actionを更新する
上ではRefresh Dataを更新している。対象データが限られているときにはこの方法でもよい。
しかし全体のデータが多い時には、MarkChangesAsSaved Actionを使う方法もある。こちらは追加したレコードのIdが自動では反映されないので、そちらの面倒を見る必要がある。
Screen Template化を検討
実際に各アプリケーションで実装していくにあたり、サンプルデータを使って
- Context Menuの構成
- 各種メッセージやUIの日本語化
- データ取得用のData Actionの構成
- Screen Actionの構成
- 更新用Server Actionの構成
のようなScreen Templateを作っておくと、標準化・作業効率化・必要スキルの簡易化などに役立ちそう。