新アーキテクチャのOutSystems UIにおける拡張機能 Client Action編

現在進行中のOutSystems UIのアーキテクチャ変更の一環で、拡張機能について新しい方式が導入されたそうなので試してみる。
拡張機能には、Client Actionによるものと、JavaScriptによるものがあり、この記事はClient Actionによるものが対象。

JavaScriptによる方法は、[新アーキテクチャのOutSystems UIにおける拡張機能 JavaScript編](https://qiita.com/jyunji_watanabe/items/f01513db7b6ca54545d6)を参照。

また、拡張機能の一般論についても、上記リンク先に書いたのでそっちを先に見てもらった方がわかりやすいかもしれない。

# 環境
Personal Environment(Version 11.17.0 (Build 36291))
Service Studio(Version 11.53.17)
OutSystems UI (Version 2.11.0)

# ドキュメント
[Provider client actions - OutSystems 11 Documentation](https://success.outsystems.com/documentation/11/building_apps/user_interface/patterns/using_mobile_and_reactive_patterns/outsystems_ui_pattern_extensibility/provider_client_actions/#provider-events)


# サンプル
[Forgeコンポーネント: HousesoftSampleReactive](https://www.outsystems.com/forge/component-overview/7086/housesoftsamplereactive)のV1.0.13。

モジュール > OutSystemsUIFlow > NewExtensibilityFeature Screenの「1. Client Actionによるパターン」

# Widgetが公開していないイベントのハンドラーを書く
DatePicker Widgetが公開するEventはInitializedとOnSelectedのみ。ただし、WidgetのベースライブラリであるJavaScriptライブラリが提供するEventに対して、Screen Actionをイベントハンドラーとして登録するClient Actionが提供されている。

この操作に対応するWidgetは同じ形式のインターフェースを持っている。

- Set[ProviderName]Event Action：イベントハンドラーを登録する
- Unset[ProviderName]Event Action：イベントハンドラーを解除する

[ProviderName]の部分は各WidgetのベースとなるJavaScriptライブラリであり、DatePickerの場合は「Flatpickr」になる。

## 対象のイベントを登録する
Providerのドキュメントを確認し、ハンドラーを書きたいイベントを特定する。
ProviderのEventに関するドキュメントは[Provider client actions - Provider events](https://success.outsystems.com/Documentation/11/Developing_an_Application/Design_UI/Patterns/Using_Mobile_and_Reactive_Patterns/OutSystems_UI_Pattern_extensibility/Provider_client_actions#provider-events)にリンクがある。

[flatpcker v4のEvents & Hooks](https://flatpickr.js.org/events/)から、例としてonCloseを選んでみる。

onClose: Inputにフォーカスを当てるとカレンダーが開くが、そのカレンダーを閉じたときに発生するイベント

## Set[ProviderName]Event Actionでイベントハンドラーを登録する

Calendar Widgetはすでに配置してある前提で、
1. WidgetのInitializedハンドラーとなるScreen Actionを作成し、そのInput Parameterとして渡ってくるWidgetのIdを保存しておく
1. イベントを登録したいタイミングで（例えばあるボタンをクリックしたとき）動作するScreen Actionを作成する
1. Set[ProviderName]Event Actionでイベントハンドラーを登録する（用意したScreen Actionの関数をJavaScript要素で取り出し、ActionのHandlerパラメータに渡す。この部分の実装方法はドキュメントを参照）

1の実装例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/11eb435f-9984-d3ce-f698-0a8f7cae863b.png)

2の実装例
まずは、Screen ActionのI/F。Input Parameterの型は、それぞれ以下の通り（flatpickrのEventに関するドキュメントが、この形式でパラメーターが渡ってくることが示している）
- SelectedDates: Object (この型である理由は次のセクションで説明）
- DateStr: Text
- Instance: Object
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/4e2e1b68-d5a5-97ff-70c3-3712f37d5dc6.png)

Screen Action内は、任意。ここではMessageを配置するだけにした。これでカレンダーが閉じられるとき、Messageが表示されるようになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/31ccd9b5-72fa-32ea-f4be-a1bb1bca1de7.png)

## イベントハンドラーとなるScreen Actionについての注意
flatpickrのドキュメントによると、各イベントのハンドラーは以下の3つの引数を受け取る

> selectedDates - an array of Date objects selected by the user. When there are no dates selected, the array is empty.
> dateStr - a string representation of the latest selected Date object by the user. The string is formatted as per the dateFormat option.
> instance - the flatpickr object, containing various methods and properties

よって、作成するScreen ActionもこれらのInput Parameterを定義しておく。
selectedDatesはDate型の配列ということだが、Input ParameterをDate Listにしておくと、実行時にエラーになる。
しかたないので、Object型として定義し、JavaScript要素を使って欲しいデータを抜き出すようにする。

JavaScript要素内のJavaScript実装例（JavaScript配列の各要素を結合してstring型にしている）。

``` js
$parameters.SelectedDatesText = $parameters.SelectedDates.join();
```

## 動作確認
以下は、「2022/10/11, 2022/10/14, 2022/10/20」の3日を選んだ状態で、カレンダーを閉じたときの動作例。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/041858f9-e286-9369-1468-cf424ec7c521.png)

このときMessage要素のパラメータは以下の通り。

```
"Set[ProviderName]Eventで登録したonCloseのイベントハンドラー。" + ArrayObjectToText.SelectedDatesText + "," + DateStr
```

これから、selectedDatesパラメータには想定通り、日付の配列が渡っており、またDateStrパラメータには『各日付をyyyy-MM-dd形式に変換したうえで「,」で結合した文字列』が渡っていることがわかる。

## Unset[ProviderName]Event Actionでイベントハンドラーの登録を解除する
一度登録したイベントハンドラーを解除するためには、Unset[ProviderName]Event Actionを使う。
パラメータは以下の通り。
- WidgetId: Setの場合と同じく、WidgetのInitializedで受け取ったWidgetIdを保存しておいて渡す
- FlatpickrEventId: Setを呼んだ時のOutput Parameterとして、解除するイベントを特定するためのIdが返ってくるので、それを保存しておいて渡す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/832d973a-2a54-b1c0-38b4-cb202013bfa4.png)

# Widgetが提供していない設定値を変更する
Widget自体のInput Parameter以外にも、Flatpickrが持っているいくつかの設定値を指定する方法が、Client Actionと設定値に対応するStructureとして提供されている。

この操作に対応するWidgetは同じインターフェースを持っている。
DatePickerの場合は[ProviderName]の部分は「Flatpickr」。

- Set[ProviderName]Configs: 対応するStructureで公開されている設定値を変更する

## テストに使うoptionを特定
Widgetは、以下のStructureを設定値指定用に公開している。ここで対象とするClient Actionは、Structureが持っているAttributeに対応する設定を変更できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/3bb68b47-534e-e3d3-f543-539196eb642e.png)

[flatpcker v4のOptions](https://flatpickr.js.org/options/)から、例としてnextArrowとprevArrowを選んでみる。
それぞれ、カレンダー上で、月を次月に切り替える/前月に切り替える役割を持つアイコンを示す。

## Set[ProviderName]Configs Actionで設定を変更する
適当なScreen Actionで、Set[ProviderName]Configs Actionを呼び出す。
以下では次月に切り替えるアイコンを「次」、前月に切り替えるアイコンを「前」という漢字に切り替える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/84aa4825-04db-8a60-b553-8443b2c59cb7.png)

WidgetのIdについては、イベントハンドラーの場合と同じく、DatePickerのInitilizedのタイミングで画面の変数に保存しておく。

## 動作確認
動作前のカレンダー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/b0989aeb-352f-cfec-7571-bbe3f46462d6.png)

動作後のカレンダー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/d53e9664-4ce8-7227-f5f7-d737032264dc.png)