0
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 1 year has passed since last update.

【UI5】OData V2 + Smart ControlでDeep createする方法

Posted at

この記事を書いたきっかけ

OData V2 + Smart Controlを使った画面で、ヘッダ + 明細という構造のデータを入力します。「登録」ボタンを押したらヘッダ、明細データを同時にDeep createでバックエンドに送信したいという要件がありました。

image.png

課題

JSONモデルであれば、「登録」ボタンを押したタイミングでODataModelのcreateメソッドを使ってディープな構造を渡すことができます。

JSONモデルでの実装イメージ
const model = this.getView().getMoel()
model.create("/EntitiySet", {
  field1: "...",
  field2: "...",
  items: [{
    field3: "",
    field4: ""
  }]
});

しかし、Smart ControlではOData Modelをバインドする必要があるため上記の方法が使えません。SAPUI5 SDKに参考になりそうなコードサンプルがあったのでこれを利用して実装してみようと思いました。

方法

サンプルアプリを使ってDeep createする方法について説明します。
ソースコード:https://github.com/miyasuta/ui5-deep-create/tree/main

使用したメタデータ(抜粋)は以下です。

            <EntityType Name="Order">
                <Key>
                    <PropertyRef Name="ID"/>
                </Key>
                <Property Name="createdAt" Type="Edm.DateTimeOffset" Precision="7"/>
                <Property Name="createdBy" Type="Edm.String" MaxLength="255"/>
                <Property Name="modifiedAt" Type="Edm.DateTimeOffset" Precision="7"/>
                <Property Name="modifiedBy" Type="Edm.String" MaxLength="255"/>
                <Property Name="ID" Type="Edm.Guid" Nullable="false"/>
                <Property Name="customer" Type="Edm.String"/>
                <NavigationProperty Name="items" Type="Collection(CatalogService.Item)" Partner="order">
                    <OnDelete Action="Cascade"/>
                </NavigationProperty>
            </EntityType>
            <EntityType Name="Item">
                <Key>
                    <PropertyRef Name="order_ID"/>
                </Key>
                <NavigationProperty Name="order" Type="CatalogService.Order" Partner="items">
                    <ReferentialConstraint Property="order_ID" ReferencedProperty="ID"/>
                </NavigationProperty>
                <Property Name="order_ID" Type="Edm.Guid" Nullable="false"/>
                <Property Name="product" Type="Edm.String"/>
                <Property Name="quantity" Type="Edm.Int32"/>
            </EntityType>

View

以下のようなビューを作成します。明細にはListBindingができるテーブル系のコントロールを使用します。ポイントは、rows="{items}"のようにリストの部分にナビゲーションプロパティを指定することです。

<mvc:View controllerName="demo.ui.controller.View1"
    xmlns:mvc="sap.ui.core.mvc" displayBlock="true"
    xmlns:m="sap.m"
    xmlns:smartForm="sap.ui.comp.smartform"
	xmlns:smartField="sap.ui.comp.smartfield"
    xmlns:smartTable="sap.ui.comp.smarttable"
    xmlns:table="sap.ui.table">
    
    <m:Page id="page" title="{i18n>title}">

        <smartForm:SmartForm id="smartForm"
			editable="true"
			validationMode="Async"
			title="{Name}">
			<smartForm:Group label="Order">
				<smartForm:GroupElement>
					<smartField:SmartField value="{customer}" />
				</smartForm:GroupElement>
			</smartForm:Group>
		</smartForm:SmartForm>  

        <table:Table
                id="table"
				rows="{items}">
			<table:extension>
				<m:Toolbar >
					<m:ToolbarSpacer />
					<m:Button id="addButton" text="Add" press="onAdd" />
					<m:Button id="deleteButton" text="Delete" press="onDelete" />
				</m:Toolbar>
			</table:extension>
            <table:columns>
                    <table:Column width="11rem">
						<m:Label text="Item No." />
						<table:template>
							<m:Text text="{itemNo}" wrapping="false" />
						</table:template>
					</table:Column>
					<table:Column width="11rem">
						<m:Label text="Product" />
						<table:template>
							<m:Input value="{product}" wrapping="false" />
						</table:template>
					</table:Column>
                    <table:Column width="11rem">
						<m:Label text="Quantity" />
						<table:template>
							<m:Input value="{quantity}" wrapping="false" />
						</table:template>
					</table:Column>    
            </table:columns>        
        </table:Table>
        

        <m:footer>
            <m:OverflowToolbar >
                <m:ToolbarSpacer />
                <m:Button text="Save" press="onSave" />
            </m:OverflowToolbar>
        </m:footer>
    </m:Page>
</mvc:View>

OData V2の場合、Smart Tableを使って入力させることができません。Smart Tableに表示するレコードはバックエンドに保存済みである必要があるためです。そのためここではsap.ui.table.Tableを使用しています。

参考
https://answers.sap.com/questions/13097516/add-new-row-in-the-smart-table.html

Controller

以下のステップでディープなリクエストを送ることができます。

  1. ODataModelのcreateEntryメソッドでヘッダのコンテキストを作り、ビューにバインドする
  2. テーブルコントロールからlistBindingを取得し、createメソッドで明細を作成する
  3. ODataModelのsubmitChangesメソッドでバックエンドにリクエストを送信する
sap.ui.define([
    "sap/ui/core/mvc/Controller",
    "sap/m/MessageToast",
    "sap/m/MessageBox"
],
    /**
     * @param {typeof sap.ui.core.mvc.Controller} Controller
     */
    function (Controller, MessageToast, MessageBox) {
        "use strict";

        return Controller.extend("demo.ui.controller.View1", {
            onInit: function () {
                const router = this.getOwnerComponent().getRouter();
                router.getRoute("RouteView1").attachPatternMatched(this._onObjectMatched, this);
                this._itemIndex = 0;
               
            },

            onSave: function () {
                //3. バックエンドにリクエストを送信
                const that = this;
                this.getView().getModel().submitChanges({
                    success: function () {
                        if (that.getView().getModel().hasPendingChanges()) {
                            MessageBox.error("Data was not fully saved");
                        } else {
                            MessageToast.show("Data saved successfully.");
                        }
                    },
                    error: function (error) {
                        MessageBox.error(JSON.stringify(error));
                    }
                })
            },

            onAdd: function () {
                //2. 明細を作成
                this._itemIndex ++;
                const table = this.getView().byId("table");                                            
                const itemsBinding = table.getBinding("rows");
                itemsBinding.create({itemNo: this._itemIndex, product: "", quantity: 1}, true /*create at end*/);
            },

            onDelete: function () {
                const table = this.getView().byId("table");    
                const selectedIndices = table.getSelectedIndices();
                const rows = table.getRows();
                selectedIndices.map(index => {
                    rows[index].getBindingContext().delete();
                });
            },

            _onObjectMatched: function () {
                //1. ヘッダのコンテキストを作りビューにバインド
                const model = this.getOwnerComponent().getModel();
                const context = model.createEntry("/Order", { 
                                        properties: {
                                            customer        : 'default'
                                        } })                    
                this.getView().setBindingContext(context);
            }
        });
    });

おわりに

OData V2では全体をSmart Controlでは作成できないことがわかりました。Smart Controlを使えば検索ヘルプが自動で(アノテーションだけで)付くのでできればSmart Controlで統一したかったのですが。
なお、OData V4 + ドラフトが使えるODataサービスであれば、Flexible Programming Modelによって入力可能なテーブルを作成することもできます。

0
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
0
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?