2
1

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】Canvas Pageを使ったFiori elementsの拡張

Posted at

はじめに

Canvas Pageを使ったFiori elementsアプリの拡張方法について調べてみました。
Canvas Pageを使うと、Fiori elementsアプリに新しいページを追加することができます。これにより、Fiori elemensアプリ内部のナビゲーションターゲットとしてCanvas Pageを持ってくることができます。

image.png

ステップ

  1. Canvas Pageのコンポーネントを作成する
  2. Canvas PageをList Reportのナビゲーション先に指定する
  3. List Reportからパラメータを受け渡す

1. Canvas Pageのコンポーネントを作成する

Canvas Pageのコンポーネント作成方法は、基本的には前回紹介したObject Pageに埋め込むコンポーネントの作成方法と同じです。前回作成したライブラリに、comp2というフォルダを新たに作成しました。
image.png
前回はフラグメントのみの構成でしたが、今回はビュー + コントローラーとしました。(どちらの構成でもちゃんと動きます)

manifest.json
{
	"_version": "1.8.0",
	"sap.app": {
		"id": "demo.testcomponent.comp2",
		"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": {
		"rootView": {
			"viewName": "demo.testcomponent.comp2.view.App",
			"type": "XML",
			"async": true,
			"id": "App"
		},		
		"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
		},
		"routing": {
			"config": {
				"routerClass": "sap.m.routing.Router",
				"viewType": "XML",
				"async": true,
				"viewPath": "demo.testcomponent.comp2.view",
				"controlAggregation": "pages",
				"controlId": "app",
				"clearControlAggregation": false
			},
			"routes": [
				{
					"name": "App",
					"pattern": "",
					"target": [
						"App"
					]
				}
			],
			"targets": {
				"App": {
					"viewName": "App"
				}
			}
		}
	}
}
component.js
sap.ui.define([
	"sap/ui/core/UIComponent",
	"sap/suite/ui/generic/template/extensionAPI/ReuseComponentSupport",
	"sap/ui/model/json/JSONModel"
], function(UIComponent, ReuseComponentSupport, JSONModel) {
	"use strict";
	
	return UIComponent.extend("demo.testcomponent.comp2.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"
				},
				
				/* Component specific properties */
				documentNumber: {
					type: "string",
					group: "specific",
					defaultValue: ""
				},

			}
		},
		
		// 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);
			
			var oLocalModel = {
				lastRefreshed: new Date()
			};
			this.setModel(new JSONModel(oLocalModel), "localModel");
		},
		
        stRefresh: function(oModel, oBindingContext, oExtensionAPI)     		    
        },
 		
	});	
});
App.view.xml
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
	xmlns:form="sap.ui.layout.form"
	xmlns:smartForm="sap.ui.comp.smartform"
	xmlns:smartField="sap.ui.comp.smartfield"
	controllerName="demo.testcomponent.comp2.controller.App" xmlns:html="http://www.w3.org/1999/xhtml">

	<App id="app">
		<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"/>
			<Text id="deliveryStatus" text="{DeliveryStatus}"/>

		</form:SimpleForm>
	</App>
	
</mvc:View>

この時点では、コントローラーには何も入れていません。

2. Canvas PageをList Reportのナビゲーション先に指定する

List Reportで行を選択したらCanvas Pageに遷移するようにします。今回は、Delivery Statusが'D'の場合はCanvas Pageに、そうでない場合はもともとのObject Pageに遷移させます。

manifest.jsonにComponentUsageを追加します。

	"sap.ui5": {
		...,
		"dependencies": {
			"minUI5Version": "1.65.6",
			"libs": {
				...,
				"demo.testcomponent": {
					"minVersion": "1.0.0"
				}
			},
			"components": {}
		},
		"componentUsages": {
			"myCanvasComponent": {
				"name": "demo.testcomponent.comp2",
				"settings": {},
				"componentData": {}
			}
		}

続いて、Object Pageの下にCanvas Pageの設定を追加します。Canvas PageはObject Pageと並列の関係なので、同じ階層に追加ます。

		"pages": {
			"ListReport|Z_C_SO_MOB67": {
				"entitySet": "Z_C_SO_MOB67",
				"component": {
					
				},
				"pages": {
					"ObjectPage|Z_C_SO_MOB67": {
						
					},
					"myCanvasPage": {
						"component": {
							"name": "sap.suite.ui.generic.template.Canvas",
							"settings": {
								"requiredControls": {
									"footerBar": true
								}
							}
						},
						"implementingComponent": {
							"componentUsage": "myCanvasComponent",
							"settings": {}
						},
						"routingSpec": {
							"noOData": true,
							"noKey": true,
							"routeName": "toCanvasPage"
						}
					}
				}

List Reportのコントローラーの拡張に以下を追加します。一覧から条件を判定してCanvas Page(またはObject Page)に遷移します。routeNameにはmanifest.jsonで指定したCanvas PageのrouteNameを設定します。

	onListNavigationExtension: function(oEvent) {
		 var oNavigationController = this.extensionAPI.getNavigationController();
		 var oBindingContext = oEvent.getSource().getBindingContext();
		 var oObject = oBindingContext.getObject();
		 if (oObject.DeliveryStatus == "D") {
		    oNavigationController.navigateInternal("", {     
		    	routeName: "toCanvasPage"
		    });  
		 } else {
		    // return false to trigger the default internal navigation
		    return false;
		 }
		 // return true is necessary to prevent further default navigation
		 return true;
	 },	

この結果、Delivery Statusが'D'の行を選択するとCanvas Pageに遷移します。
ただし、画面にコンテキストがバインドされていません。
image.png

ドキュメントを見ると以下の説明があり、何もしなくてもバインドされてくれそうですが・・・

Note that the context of the parent page is passed to the canvas page in this scenario. In this example, this means that controls that are embedded in the theImplementingComponentQualifiedName component can be directly bound to properties of theMainEntitySet.

私のやり方が間違っているのかもしれませんが、これ以上はわからなかったので、バインド用のパスをナビゲーションの時に渡すことにします。

3. List Reportからパラメータを受け渡す

List Report側

ナビゲーションの際にパラメータを渡すには、manifest.jsonのrouteingSpecで、noKeyをfalseにします。

                        "routingSpec": {
                            "noOData": true,
                            "noKey": false,
                            "routeName": "toCanvasPage"
                        }

ナビゲーションの際にbindingContextからパスを取得し、エンコードしてナビゲーションのパラメータに渡します。エンコードするのは、スラッシュ(/)が入っているとナビゲーションがうまく動かないためです。

		 if (oObject.DeliveryStatus == "D") {
		 	var encodedPath = encodeURIComponent(oBindingContext.getPath());
		    oNavigationController.navigateInternal(encodedPath, {     
		    	routeName: "toCanvasPage"
		    });  
		 } 

Canvas Page側

Component.jsにパラメータを受け取る処理を追加します。

Component.js
        stRefresh: function(oModel, oBindingContext, oExtensionAPI) {
		    this.oExtensionAPI = oExtensionAPI;
		    var oNavigationController = oExtensionAPI.getNavigationController();    
		    var aKeys = oNavigationController.getCurrentKeys();    
		    var sPath = decodeURIComponent(aKeys[aKeys.length - 1]);
		    var oComponentModel = this.getComponentModel();    
		    oComponentModel.setProperty("/sPath", sPath);     		    
        }

コントローラーでパスを取得し、フォームにバインドします。

App.controller.js
		onInit: function () {
			var sPath = this.getOwnerComponent().getComponentModel().getProperty("/sPath");
			this.byId("simpleForm").bindElement(sPath);
		},

以上の設定により、Canvas Pageにデータが表示されるようになりました。
image.png

Canvas Pageは使えるのか?

Fiori elementsアプリから別のページに遷移することは、External Navigationを使っても実現できます(※)。その際は遷移先のアプリの種類に制限はないので、そちらの方が便利な気がします。
Canvas Pageを使うメリットは、Canvas Pageをターゲットマッピングに登録しなくてもいいことくらいでしょうか。

Example: Replacing Standard Navigation in a Responsive Table in the List Report

2
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?