2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Fiori】Object Pageにコンポーネントを埋め込む方法

Last updated at Posted at 2020-06-20

はじめに

以下のSAPブログに、Fiori elementsアプリを拡張するさまざまな方法が紹介されていました。その中でReuse Componentsというものがあるのを知ったので、実装してみようと思いました。
Extending SAP Fiori elements Applications – What you need to know
ドキュメント

この記事で紹介すること

  1. コンポーネントを作ってObject Pageに埋め込む
  2. コンポーネントの表示位置を変更する
  3. Object Pageのデータ変更に反応する

1. コンポーネントを作ってObject Pageに埋め込む

Fiori elementsに埋め込むためのコンポーネントは、通常のコンポーネントとは作りが変わります。よって通常のコンポーネントと共有することはできません。

ライブラリの作成

コンポーネント用のライブラリを用意します。comp1が埋め込むコンポーネントです。
image.png

ライブラリのmanifest.jsonにコンポーネントの情報を追加します。
image.png

コンポーネントの作成

以下はcomp1の中身です。コンポーネント側ではObject Pageのコンテキストがそのまま使用可能なので、manifest.jsonではモデルを定義していません。ここでデフォルトモデルを定義した場合、Object Pageのモデルと衝突して思った通りにデータが表示されません。コンポーネント独自のモデル定義が必要な場合は、名前つきモデルにします。

manifest.json
{
	"_version": "1.8.0",
	"sap.app": {
		"id": "demo.testcomponent.comp1",
		"type": "component",
		"embeddedBy": "../",
		"i18n": "i18n/i18n.properties",
		"applicationVersion": {
			"version": "1.0.0"
		},
		"title": "{{compTitle}}",
		"description": "{{compDescription}}"
	},
	"sap.ui": {
		"technology": "UI5",
		"icons": {
			"icon": "",
			"favIcon": "",
			"phone": "",
			"phone@2": "",
			"tablet": "",
			"tablet@2": ""
		},
		"deviceTypes": {
			"desktop": true,
			"tablet": true,
			"phone": true
		},
		"supportedThemes": [
			"sap_fiori_3"
		]
	},
	"sap.ui5": {
		"resources": {
			"js": [],
			"css": []
		},
		"dependencies": {
			"minUI5Version": "1.65.6",
			"libs": {
				"sap.ui.core": {
					"lazy": false
				},
				"sap.m": {}
			},
			"components": {}
		},
		"models": {
			"i18n": {
				"type": "sap.ui.model.resource.ResourceModel",
				"uri": "i18n/i18n.properties"
			}
		},
		"contentDensities": {
			"compact": true,
			"cozy": true
		}
	}
}

画面は簡単なFormとします。

myComponent.fragment.xml
<core:FragmentDefinition
	xmlns="sap.m"
	xmlns:smartForm="sap.ui.comp.smartform"
	xmlns:smartField="sap.ui.comp.smartfield"	
	xmlns:core="sap.ui.core">
	
		<smartForm:SmartForm id="smartForm" title="{i18n>Title}" entityType="Z_C_SO_MOB67Type">
			<smartForm:Group label="{i18n>Group1}">
				<smartForm:GroupElement>
					<smartField:SmartField value="{CreatedAt}" />
				</smartForm:GroupElement>
				
				<smartForm:GroupElement>
					<smartField:SmartField value="{CreatedBy}" />
				</smartForm:GroupElement>				
			</smartForm:Group>
		</smartForm:SmartForm>
	
</core:FragmentDefinition>

Fiori elements用のコンポーネントと通常のコンポーネントとの違いは、Component.jsの実装部分です。

Component.js
sap.ui.define([
	"sap/ui/core/UIComponent",
	"sap/suite/ui/generic/template/extensionAPI/ReuseComponentSupport"
], function(UIComponent, ReuseComponentSupport) {
	"use strict";
	
	return UIComponent.extend("demo.testcomponent.comp1.Component", {
		metadata: {
			manifest: "json",
			properties: {
				/* Standard properties for reuse components */
				uiMode: {
					type: "string",
					group: "standard"
				},
				semsnticObject: {
					type: "string",
					group: "standard"
				},
				stIsAreaVisible: {
					type: "boolean",
					group: "standard"
				}
		},
		
		// Standard life time event of a component. Used to transform this component into a reuse component for Fiori Elements
		init: function () {
			//Transform this component into a reuse component for Fiori Elements:
			ReuseComponentSupport.mixInto(this, "compModel");
			// Defensive call of init of the super class:
			(UIComponent.prototype.init || jQuery.noop).apply(this, arguments);
			
		},
	
});

Elements用のコンポーネントには以下の特徴があります。

・Object Pageの情報を表すパラメータを持っている

パラメータ 説明
uiMode Object Pageの画面モード。"Create", "Display", または "Edit"が設定される
semanticObject Object Pageに表示されているセマンティックオブジェクト
stIsAreaVisible Reuse Componentが画面に表示されているか(true: 表示されている)

・initメソッドの中でElements用のコンポーネントに変換する
以下のメソッドで、UIComponentがElements用のコンポーネントに変換されます。
ReuseComponentSupport.mixInto(this, "<プロパティモデルの名前>");
<プロパティモデルの名前>を渡すとuiModeなどのパラメータがJSONモデルに格納され、コンポーネントのビューから使用できるようになります。 (参考:APIリファレンス

Component.jsの残りの部分は以下のようにしました。シンプルにフラグメントを取得して表示します。

		
		createContent: function () {
			//Return a fragment
			var oFragment = this._getFragment();
			return oFragment;
		},
		
		_getFragment: function () {
			if (!this._oFragment) {
				this._oFragment = sap.ui.xmlfragment(this.getId(), "demo.testcomponent.comp1.fragment.myComponent", this);
			}
			return this._oFragment;
		}
		
	});

Object Pageに埋め込み

Object Pageがあるアプリのmanifest.jsonにライブラリ、およびコンポーネント使用の情報を追加します。
image.png

続いて、pagesセクションに埋め込むコンポーネントの情報を設定します。
image.png

結果

コンポーネントが表示されました。
image.png

2. コンポーネントの表示位置を変更する

デフォルトではコンポーネントはObject Pageの最後のセクションとして追加されます。ここでは、以下の方法について見ていきます。

  • 既存セクションのサブセクションとして追加
  • 任意の位置にセクションとして追加

既存セクションのサブセクションとして追加

Order Infromationセクションのサブセクションとしてコンポーネントを追加してみます。
image.png

UI.Facetsアノテーションの中からターゲットとなるUI.CollectionFacetのIDを探します。<PropertyValue Property="ID" String="HeaderFacet"/>より、"HeaderFacet"がIDです。

				<Annotation Term="UI.Facets">
					<Collection>
						<Record Type="UI.CollectionFacet"><PropertyValue Property="Label" String="Order Information"/><PropertyValue Property="ID" String="HeaderFacet"/>
							<PropertyValue Property="Facets">
								<Collection>
									<Record Type="UI.ReferenceFacet"><PropertyValue Property="Label" String="Basic Information"/><PropertyValue Property="ID" String="BasicGroup"/><PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#BasicFieldGroup"/></Record>
									<Record Type="UI.ReferenceFacet"><PropertyValue Property="Label" String="Order Status"/><PropertyValue Property="ID" String="StatusGroup"/><PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#StatusFieldGroup"/></Record>
								</Collection>
							</PropertyValue>
						</Record>
						<Record Type="UI.ReferenceFacet"><PropertyValue Property="Label" String="Item"/><PropertyValue Property="ID" String="ItemFacet"/><PropertyValue Property="Target" AnnotationPath="to_Item/@UI.LineItem"/></Record>
					</Collection>
				</Annotation>

manifest.jsonの"leadingSectionIdOrPath"に、上で確認したIDを指定します。(CollectionFacetの場合はID、ReferenceFacetの場合はアノテーションパスを指定します)

						"embeddedComponents": {
							"myFirstComponentEmbeding": {
								"id": "myFirstComponentEmbeding",
								"componentUsage": "myReuseComponent",
								"title": "{{myFirstComponentTitle}}",
								"leadingSectionIdOrPath": "HeaderFacet"
							}
						}

結果は以下のようになります。
image.png

任意の位置にセクションとして追加

VisualEditorを使うと、セクションを任意の位置に移動することができます。

事前にプロジェクトの設定でVisualEditorで使うRun Configurationを設定しておきます。これがないとコンポーネントのライブラリを読み込むことができません。
image.png

VisualEditorを編集モードにしたら、コンポーネントのセクションをつかんで任意の場所にドラッグ&ドロップします。
image.png
Order Informationの下に移動しました。
image.png
結果は以下のようになります。
image.png

3. Object Pageのデータ変更に反応する

Object Pageのデータが変更されたときにコンポーネントのデータをリフレッシュする方法について紹介します。

コンポーネント側の設定

コンポーネント側ではstRefreshというメソッドを定義します。このメソッドはObject Pageがロードされたときや、Object Pageでの変更が保存されたときに呼ばれます。

Component.js
		init: function () {
			//...
		},
		
        stRefresh: function(oModel, oBindingContext, oExtensionAPI) {
		    this.oModel = oModel;
		    this.oBindingContext = oBindingContext;
		    this.oExtensionAPI = oExtensionAPI;
		    this._doRefresh();
        },
        
        _doRefresh: function () {
        	this.getModel("localModel").setProperty("/lastRefreshed", new Date());	
        },

画面に最終リフレッシュ時刻を表示するようにします。(諸般の事情によりSmartFormからSimpleFormに変更しました)

	<form:SimpleForm id="simpleForm">
		<Label text="Created At" labelFor="createdAt"/>
		<Text id="createdAt" text="{
			path: 'CreatedAt',
			type: 'sap.ui.model.type.DateTime',
			formatOptions: {
				style: 'medium'
			}}"/>
		<Label text="Created by" labelFor="createdBy"/>
		<Text id="createdBy" text="{CreatedBy}"/>
		<Label text="Delivery Status" labelFor="deliveryStatus"/>
		
		<!--最終リフレッシュ時刻を表示-->
		<Label text="Last Refreshed" labelFor="lastRefreshed" />
		<Text id="lastRefreshed" 
			text="{
				path: 'localModel>/lastRefreshed',
				type: 'sap.ui.model.type.DateTime',
				formatOptions: {
					style: 'medium'
			}}" />			
	</form:SimpleForm>

画面には以下のように表示されます。
image.png

Object Page側の設定

Object Page側でデータを編集中にリアルタイムにコンポーネントをリフレッシュしたい場合、以下の設定が必要になります。

※リアルタイムなリフレッシュが不要な場合、コンポーネントのstRefreshの実装だけでよいです
※Object Pageと共有しているコンテキストはリアルタイムにコンポーネントに反映されるので、特に何もする必要はありません

ここでは、Delivery Statusを変更したらコンポーネントをリフレッシュするようにします。manifest.jsonにstRefreshTriggerというプロパティを追加します。

						"embeddedComponents": {
							"myFirstComponentEmbeding": {
								"id": "myFirstComponentEmbeding",
								"componentUsage": "myReuseComponent",
								"title": "{{myFirstComponentTitle}}",
								"settings": {
									"stRefreshTrigger": "{DeliveryStatus}"
								}
							}
						}

・複数の項目のうちいずれかが変更された場合にリフレッシュするとき
"{Price}{Supplier}"
・複数の項目が変更された場合にリフレッシュするとき
"{= ${Price}+${Supplier}}"

上記の設定により、保存ボタンを押す前にもコンポーネントのリフレッシュが呼ばれるようになります。

使い道

Reuse Componentを使うことで、Fiori elements単体ではできないことも実現できるようになります。そのよい例が添付ファイルです。以下のブログに標準のファイル添付コンポーネントをFiori Elementsアプリに埋め込む方法が紹介されています。
Attachment Service to your rescue in S4HANA via Fiori Elements using Reuse Components (GOS)

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?