【SAPUI5】F4ヘルプ風検索ヘルプの作り方

##概要
SAPGUIでは「F4」ヘルプ（※）と呼ばれる検索ヘルプで、コードや値の検索ができます。
今回の記事ではSAPUI5で同じような機能を実装する方法について、説明します。
※項目の横にあるボタン、またはF4キーを押すとヘルプが立ち上がる

##アプリケーションの構造
今回登場するのは、ビュー、コントローラ、モデル(Data.json)と、ポップアップ用のフラグメントです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/e61f5fed-f708-01ed-818e-205603dbbd69.png)

##フラグメントとは
フラグメントとは、ビューの一種で複数の画面で使う部品のようなものです。フラグメントは必ずビューの中で呼ばれます。
ビューは対応するコントローラーを持つのに対して、フラグメントはコントローラーを持ちません。フラグメントで何か機能を実行したい場合は、ビューのコントローラにメソッドを実装します。ビューのコントローラーを間借りするイメージですね。

##ゴール
ボタンを押すと、都道府県のリストを表示するポップアップが出力されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/5962d394-db86-52fc-e26d-45f261dc3747.png)

<img width="193" alt="valuehelp.png" src="https://qiita-image-store.s3.amazonaws.com/0/276021/8bf810d7-d5b7-f656-d9d1-4eff987df5c3.png">
値を選択すると、入力フィールドに持ち込まれます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/4a16c68c-a61e-8d5b-1488-655757c6cfe2.png)


##実装
###ステップ
前提：[入門編の記事まとめ](https://qiita.com/tami/items/53990a14e5ca919ec35a)
※今回は一から作っているので上記のアプリと一部内容が異なるかもしれませんがご了承ください

1. ビューの実装
2. フラグメントの実装
3. モデルの実装
4. コントローラの実装

###1. ビューの実装
App.view.xml

```xml
<mvc:View 
	controllerName="odatatest.controller.App" 
	xmlns="sap.m" 
	xmlns:f="sap.ui.layout.form"
	xmlns:mvc="sap.ui.core.mvc">
	<App id="idApp">
		<pages>
			<Page title="{i18n>pageTitle}">
				<content>
					<Panel headerText="{i18n>panelHeader}">
						<content>
							<f:SimpleForm editable="true">
								<f:content>
									<Label text="都道府県" labelFor="idPref" />
									<Input id="idPref" showValueHelp="true" valueHelpRequest="onValueHelp1"/>						
								</f:content>
							</f:SimpleForm>
						</content>
					</Panel>					
				</content>
			</Page>
		</pages>
	</App>
</mvc:View>
```

ポイントは、Inputコントロールのプロパティです。`showValueHelp="true"` は検索ヘルプ用のボタンを表示し、`valueHelpRequest="onValueHelp1"`はボタンが押されたときのメソッドを指定します。onValueHelp1メソッドはこの後コントローラーに実装します。

###2. フラグメントの実装

```xml
<core:FragmentDefinition xmlns:core="sap.ui.core" xmlns="sap.m">
	<SelectDialog confirm="onConfirm"></SelectDialog>
</core:FragmentDefinition>
```
とってもシンプル！
これは確認用のポップアップを出す画面です。実際の中身はコントローラーの中で設定します。

###3. モデルの実装
Data.json

```json
{
	"Prefecture": [
		{"name": "北海道"},
		{"name": "青森"},
		{"name": "秋田"},
		{"name": "岩手"},
		{"name": "宮城"},
		{"name": "福島"},
		{"name": "茨城"}
		]
```

ヘルプに表示されるデータを定義します。
manifest.jsonにもモデルの定義を追加します。

```json
		"models": {
			"i18n": {
				"type": "sap.ui.model.resource.ResourceModel",
				"settings": {
					"bundleName": "odatatest.i18n.i18n"
				}
			},
			"mData":{
				"type": "sap.ui.model.json.JSONModel",
				"uri": "model/Data.json"
			}
		}
```



###5. コントローラの実装
App.controller.js

```javascript
sap.ui.define([
	"sap/ui/core/mvc/Controller",
], function (Controller) {
   "use strict";
   return Controller.extend("odatatest.App", {
   		onValueHelp1: function(oEvent){
   			//1. フラグメントをインスタンス化
   			var oFragment = new sap.ui.xmlfragment("odatatest.view.ValueHelp", this);
   			//2. ビューとフラグメントをひもづけることによってモデルにアクセスできるようにする
   			this.getView().addDependent(oFragment);
   			//3. フラグメントにリストを追加し、モデルのデータをバインドする
   			oFragment.bindAggregation("items", {
   				path: "mData>/Prefecture",
   				template: new sap.m.StandardListItem({
   					title: "{mData>name}"
   				})
   			});
   			//4. フラグメント画面を開く
   			oFragment.open(); 	  	   			
   		}           
 
   });
});		
```
検索ボタンが押されたときに実行するメソッドを実装します。
フラグメントの画面にStandardListItemコントロール（リスト）を追加し、そこにモデルのデータをバインドします。

続いて、ポップアップで行を選択したときに、画面に値を持ち込むメソッド(onConfirm)を実装します。

フラグメント（再掲）

```xml
<core:FragmentDefinition xmlns:core="sap.ui.core" xmlns="sap.m">
	<SelectDialog confirm="onConfirm"></SelectDialog>
</core:FragmentDefinition>
```

```javascript
sap.ui.define([
	"sap/ui/core/mvc/Controller",
], function (Controller) {
   "use strict";
   return Controller.extend("odatatest.App", {
   		onValueHelp1: function(oEvent){
   			//インプットフィールドのIDをグローバル変数に格納
   			this.inputId = oEvent.getSource().getId();
   			//以下省略

   		},
   		
   		onConfirm: function(oEvent){
   			//選択された行のタイトルを取得
   			var selectedItem = oEvent.getParameter("selectedItem").getTitle();
   			//インプット項目に値を設定
   			this.getView().byId(this.inputId).setValue(selectedItem);
   		}  
   });
});
```
まず、さきほど実装したonValueHelp1メソッドに1行追加します。
this（コントローラーのインスタンス）にinputIdという変数を追加します。この変数は、検索ヘルプボタンが押された項目のidを格納するためのものです。
フラグメントを生成するときに`var oFragment = new sap.ui.xmlfragment("odatatest.view.ValueHelp", this);`という書き方をしましたが、thisという引数によってフラグメント側でもコントロールのインスタンスを参照することができるようになります。onConfirmというメソッドはフラグメントから呼び出されるものなので、そのままだとビューのコントローラーにアクセスすることができません。

続いてonConfirmメソッドでは、選択された行のタイトルを取得し、画面項目に設定します。

##フラグメントで複数の検索ヘルプを実装
せっかくなので、もう一つ検索ヘルプを作ってみましょう。フラグメントを使う利点が実感できると思います。

ビューに「好きなスポーツ」という項目を追加します。検索ボタンが押されたときのメソッドは`onValueHelp2`です。

```xml
							<f:SimpleForm editable="true">
								<f:content>
									<Label text="都道府県" labelFor="idPref" />
									<Input id="idPref" showValueHelp="true" valueHelpRequest="onValueHelp1"/>
									<Label text="好きなスポーツ" labelFor="idSport" />
									<Input id="idSport" showValueHelp="true" valueHelpRequest="onValueHelp2"/>						
								</f:content>
							</f:SimpleForm>
```

Data.jsonに"Sports"というリストを追加します。

```json
	"Sports": [
		{"name": "サッカー"},
		{"name": "野球"},
		{"name": "バスケットボール"},
		{"name": "野球"},
		{"name": "水泳"},
		{"name": "陸上"},
		{"name": "テニス"}
		]	
```

コントローラーですが、再利用を考えてフラグメントをインスタンス化して開くところをプライベートメソッドにします。引数でモデルへのパスを受け取り、フラグメントへバインドする際に使います。

```javascript
   		_ValueHelp: function(oEvent, path){
   			this.inputId = oEvent.getSource().getId();
   			var oFragment = new sap.ui.xmlfragment("odatatest.view.ValueHelp", this);
   			this.getView().addDependent(oFragment);
   			oFragment.bindAggregation("items", {
   				path: path, //引数に変更
   				template: new sap.m.StandardListItem({
   					title: "{mData>name}"
   				})
   			});
   			oFragment.open(); 	  			
   		},
```

呼び出し側はこのようになります。こうしておけば、新規の検索ヘルプが必要になっても簡単に増やせますね。（ただし、この方法では同じビュー内のみ）

```javascript
   		onValueHelp1: function(oEvent){
   			this._ValueHelp(oEvent, "mData>/Prefecture");
   		},

   		onValueHelp2: function(oEvent){
   			this._ValueHelp(oEvent, "mData>/Sports");
   		},
```

###結果
「好きなスポーツ」の検索ボタンをクリックすると、スポーツの一覧が表示されました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/98b3ca8a-6989-c44f-a5f2-c1f8064fcea3.png)

<img width="190" alt="valuehelp2.png" src="https://qiita-image-store.s3.amazonaws.com/0/276021/5ad674f7-30ea-ae0f-955b-fdc708637d4c.png">