LoginSignup
1
0

More than 1 year has passed since last update.

Flexible Programming Model: 登録と照会で別のページを使う試みでできたこと、できなかったこと

Last updated at Posted at 2022-12-28

はじめに

Fiexible Programming Modelを使うと、Fiori elementsのテンプレートで作ったアプリにカスタムページを差し込むことが可能です。このシナリオに関して、以下のYoutube動画で興味深い例が紹介されていました。

それは、List Reportから開く「登録画面」にカスタムページを使うというものでした。
image.png

これは使えそう、ということで自分でも試してみました。この記事では、試してみた結果できたこと、できなかったことについて記録します。

チャレンジ

元の動画では登録画面をカスタムページに置き換えるのみでしたが、照会画面は通常のObject Pageを使いたいと思ったので、以下のようなことができるか試してみました。

  • List Reportで"Create"ボタンを押したらカスタムページを開く
  • テーブル行をクリックしたらObject Pageを開く

image.png

結果だけ先に知りたい方は、動作確認以降のセクションをお読みください。

前提

  • OData V4を使用していること
  • ドラフトが有効であること
    以下のリポジトリにあるCAPのプロジェクトをベースに作成します。
    https://github.com/miyasuta/flex-orders

UIアノテーションは以下のファイルで設定しています。
https://github.com/miyasuta/flex-orders/blob/main/srv/order-srv-ui.cds

ステップ

  1. List Reportのテンプレートでアプリを生成
  2. カスタムページを作成
  3. Routingの設定
  4. コントローラーの拡張

1. List Reportのテンプレートでアプリを生成

ウィザードで"List Report Page"を選択してアプリを生成します。
image.png

初期状態では、"Create"をクリックするとObject Pageが開きます。
image.png
image.png

2. カスタムページを作成

以下のGitリポジトリを参考に、Custom Page用のビューとコントローラーを作成します。
https://github.com/SAP-samples/fiori-elements-v4-cap-advanced/tree/fpmVideos/app/travel_processor/webapp/ext/view

image.png

ビュー

2ステップ + プレビュー画面のウィザードです。各ステップではBuilding Blocks(ネームスペースにmacros:とついているコントロール)を使用しています。プレビュー画面では、各ステップで入力した項目を照会モードで表示させるつもりです。

webapp/ext/view/OrderCreate.view.xml
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns:macros="sap.fe.macros" xmlns:form="sap.ui.layout.form" id="review" controllerName="flex.createwizard.ext.view.OrderCreate" xmlns="sap.m">
    <NavContainer id="wizardNavContainer">
        <pages>
            <Page id="createOrderPage" title="Guided Order Creation">
                <content>
                    <Wizard id="CreateOrderWizard" class="sapUiResponsivePadding--header sapUiResponsivePadding--content" complete="reviewOrder">
                        <WizardStep id="stepCustomer" title="Customer" validated="true">
                            <VBox width="800px">      
                                <Text text="Select the customer." />
                                <macros:Field metaPath="customer_ID" id="customer" />
                            </VBox>
                        </WizardStep>
                        <WizardStep id="stepItems" validated="true" title="Items">
                            <macros:Table metaPath="to_Items/@com.sap.vocabularies.UI.v1.LineItem" id="items" busy="{ui>/isBusy}" />
                        </WizardStep>
                    </Wizard>
                </content>
                <footer>
                    <OverflowToolbar>
                        <ToolbarSpacer />
                        <Button id="cancelButton" text="Cancel" press="cancelDocument" />
                    </OverflowToolbar>
                </footer>
            </Page>
            <Page id="reviewPage" title="Review New Order">
                <content>
                    <macros:Form readOnly="true" metaPath="@com.sap.vocabularies.UI.v1.FieldGroup#main" id="reviewGeneral" />
                    <macros:Table readOnly="true" enableExport="false" isSearchable="false" personalization="false"
                        metaPath="to_Items/@com.sap.vocabularies.UI.v1.LineItem" id="itemsDisplay"  />
                    <MessageStrip class="sapUiSmallMarginBottom" type="Warning" text="By clicking on Create New Order you accept you read and accept our internal order guidelines." showIcon="true" />
                    <Button text="Create New Order" press="createOrder" type="Emphasized" />
                </content>     
            </Page>
        </pages>
    </NavContainer>
</mvc:View>

コントローラー

ビューには3つのボタンがあり、コントローラーの以下のイベントハンドラが対応しています。
reviewOrder: "Review"ボタンを押したときに、reviewPageを表示する
createOrder: "Create New Order"ボタンを押したときに、ドキュメントを保存し、List Report画面に戻る
cancelDocument: "Cancel"ボタンを押したときに、ドキュメントを破棄し、List Report画面に戻る

sap.ui.define(["sap/fe/core/PageController", "sap/m/MessageToast"], function(PageController, MessageToast) {
	"use strict";

	return PageController.extend("flex.createwizard.ext.view.OrderCreate", {

        reviewOrder: function () {
			this.byId("wizardNavContainer").to(this.byId("reviewPage"));
		},

        createOrder: function () {
            var that = this;
			this.editFlow.saveDocument(this.getView().getBindingContext()).then(function(){
                that.routing.navigateToRoute('OrdersList');
            })
		},

        cancelDocument: function () {
            var that = this;
			this.editFlow.cancelDocument(this.getView().getBindingContext(), {
                control: this.byId("cancelButton")
            }).then(function(){
                that.routing.navigateToRoute('OrdersList');
            })
		}
	});
});

注目したいのが、this.editFlow.saveDocumentthis.editFlow.cancelDocumentというメソッドです。これらはExtensionAPIで提供されるEditFlowというクラスのメソッドで、ODataのエンティティを操作することができます。
Extension APIを使うことができるのは、コントローラーが通常見るsap.ui.core.mvc.Controllerではなくsap.fe.core.PageControllerというFlexible Programming Model用の特別なクラスを使っているためです。

3. Routingの設定

作成したカスタムページを表示させるため、manifest.jsonでRoutingの設定を行います。

まず、"routes"セクションにカスタムページ用のルートを追加します。"pattern"にはもともとObjectPageで使用していたパターンを指定します。これは、"Create"ボタンが押されるとURLのハッシュ(#)以降が自動的にOrders({key})になるためです。ObjectPageには別のパターンを指定します。ここではOrderDetail({key}):?query:としました。

変更前
    "routing": {
      "config": {},
      "routes": [
        ...,
        {
          "pattern": "Orders({key}):?query:",
          "name": "OrdersObjectPage",
          "target": "OrdersObjectPage"
        },
        ...
      ]
変更後
    "routing": {
      "config": {},
      "routes": [
        ...,
        {
          "pattern": "Orders({key}):?query:",
          "name": "CreateWizard",
          "target": "CreateWizard"
        },
        {
          "pattern": "OrderDetail({key}):?query:",
          "name": "OrdersObjectPage",
          "target": "OrdersObjectPage"
        },
        ...
      ]

次に、"targets"セクションにカスタムページ用のターゲットを追加します。カスタムページでは、sap.fe.core.fpmというコンポーネントを指定します。これにより、ビューでBuilding Blocksを使えるようになります。
参考:SAP Fiori Elements: Flexible Programming Model Explorer > Building Blocks > Usage in Custom Apps

      "targets": {
        "OrdersList": {
          ...
        },
        "CreateWizard": {
            "type": "Component",
            "id": "entryPage",
            "name": "sap.fe.core.fpm",
            "options": {
                "settings": {
                    "viewName": "flex.createwizard.ext.view.OrderCreate",
                    "entitySet": "Orders"
                }
            }
        },
        "OrdersObjectPage": {
          ...
        },

ここまでで"Create"ボタンを押すとウィザードが開くようになりました。しかし、List Reportでテーブルの行を選択したときにも、カスタムページが開いてしまいます。
image.png
image.png
これは、URLのハッシュ以降が#/Orders(1)となっているためです。このパターンはカスタムページのルートに一致するため、カスタムページが開いてしまうのです。

4. コントローラーの拡張

テーブル行をクリックしたときにはObject Pageを開くように、コントローラーを拡張します。

manifest.json

まず、manifest.jsonの"sap.ui5"セクションに以下の設定を追加し、拡張したソースファイルの位置を指定します。

  "sap.ui5": {
    ...
    "extends": {
        "extensions": {
            "sap.ui.controllerExtensions": {
                "sap.fe.templates.ListReport.ListReportController": {
                    "controllerName": "flex.createwizard.ext.controller.OrdersList"
                }
            }
        }
    }
  }

コントローラー拡張

上記で指定した位置にコントローラー拡張用のファイルを作成します。
image.png
ここでは、Routing Extensibilityと呼ばれるコントローラー拡張を使用して、Object Pageへナビゲーションする直前の動作を変更します。manifest.jsonで定義された"OrdersObjectPage"のルートへ遷移させるようにしています。

OrdersList.controller.js
sap.ui.define(
	[
		"sap/ui/core/mvc/ControllerExtension",
	],
	function(ControllerExtension, ) {
		"use strict";
		return ControllerExtension.extend("flex.createwizard.ext.controller.OrdersList", {
			override: {
				routing: {					
					onBeforeNavigation: function(mNavigationParameters) {
						const oBindingContext = mNavigationParameters.bindingContext;
                        const parameters = {
                            key: /\(([^)]*)\)/.exec(oBindingContext.getPath())[1]
                        };
						this.base.getExtensionAPI().routing.navigateToRoute("OrdersObjectPage", parameters)
						return true;
					}
				}
			}
		});
	}
);

ここまでの設定でObject Pageは開きますが、Object Pageにデータが表示されません。
image.png

manifest.jsonのターゲットに"contextPattern"を追加するとデータが表示されるようになります。推測ですが、Object PageのパターンをOrderDetail({key}):?query:と変更したことにより、キー情報が取ってこられなくなったのだと思われます。contextPatternによってkeyがどのようにコンテキストにマッピングされるかを認識させることができるのだと理解しました。
image.png

動作確認

登録画面

"Create"ボタンを押すと、登録画面(カスタムページ)が開きます。
image.png
テーブルから明細の入力もできます。
image.png
Reviewページでは、以下の問題がありました。

  • フォームをreadOnlyに設定したにも関わらず、入力できてしまう
  • テーブルにデータが表示されない
    image.png

SAP Communityに質問してみたところ、以下の回答を得ました。

1つのページでまだ保存されていない状態のデータを、入力・照会の2つのモードで表示させるというのは良いやり方ではない、という結論です。これはFlexible Programming Modelの制約というよりも、使い方がよくない例でした。

Object Pageへの遷移

テーブル行をクリックしてObject Pageに遷移します。
image.png
Object Pageが開きました。URLのパターンは#/OrderDetail(ID=8a5a163c-7715-4649-adc8-c9877fb1dd7b,IsActiveEntity=true)となっています。
image.png
"Edit"ボタンを押すと、カスタムページになりました。このときのURLパターンは#/Orders(1)となっていました。
image.png
「"Edit"ボタンを押すとURLパターンが自動的にもともとのObject Pageのパターンに変わり、そのパターンはカスタムページで使用しているためカスタムページが開いてしまう」という動きのようです。
残念ながら、Editボタンを押したときのルートパターンを制御する方法は見つかっていません。

考察

今回は、登録用のカスタムページを、もともとObject Pageを表示していたパターンで開くようにしたため、編集モードに切り替えるとカスタムページが開いてしまいました。これを回避するには、以下のような方法をとる必要があるのではないかと考えます。

案1

  • 登録用のカスタムページは既存のページとは別のパターンで開くようにする
  • カスタムの「登録」ボタンを作成し、カスタムボタンが押されたらカスタムページを開く
    ※標準の「登録」ボタンをどうやって消すのかは調査が必要

案2

  • 登録画面はBuilding Blocksを使用して独立したアプリケーションとして作り、カスタムの「登録」ボタンが押されたら登録画面にナビゲーションする
1
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
1
0