16 Step 16: Dialogs and Fragments
fragments 是一个轻量级的UI组件,可以重用,但没有任何controller。
当你想定义一个跨多个视图的,特定的ui的一部分时,可以选择fragments。
一个fragment里面可以包括一个到多个控件,在运行的时候,视图中的fragments中的控件的内容会像普通视图中的content内容一样,被包含在视图的DOM中。这样我们可以像访问普通视图的控件一样,直接访问fragments中的控件。
当然,也有一些控件不会成为视图的一部分,例如对话框。
添加一个对话框到应用程序中,对话框打开在常规的应用程序内容之上,因此不属于特定的视图,所以必须在controller的某个地方进行实例化。
另外由于需要尽可能灵活的重用构件,并且不能将对话框指定为view,所以我们将创建包含dialog的XML fragment。
修改 HelloPanel.view.xml
<mvc:View controllerName="sap.ui.demo.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel headerText="{i18n>helloPanelTitle}" class="sapUiResponsiveMargin" width="auto" > <content> <Button id="helloDialogButton" text="{i18n>openDialogButtonText}" press=".onOpenDialog" class="sapUiSmallMarginEnd"/> <Button text="{i18n>showHelloButtonText}" press=".onShowHello" class="myCustomButton"/> <Input value="{/recipient/name}" valueLiveUpdate="true" width="60%"/> <FormattedText htmlText="Hello {/recipient/name}" class="sapUiSmallMargin sapThemeHighlight-asColor myCustomText"/> </content> </Panel> </mvc:View>
给控件一个唯一的标示是一个良好的习惯,比如这里的id="helloDialogButton",可以通过这个标示很容易的对控件进行操作,如果不指定id的话,sapui5会在运行的时候,自动生成一个id。
新加HelloDialog.fragment.xml
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" > <Dialog id="helloDialog" title="Hello {/recipient/name}"> </Dialog> </core:FragmentDefinition>
将定义的dialog放入fragment中,并且创建一个新的xml文件。
fragment位于core的命名空间中,因此在FragmentDefinition标记中为它添加了一个xml名称空间。
fragment没有controller,不占用内容,也没有控件实例,只是一组重用空间的容器。
这里我理解为,view中的<button>会有button的实例,button点击时,会触发button实例的方法。但是fragment没有实例的,所以也没有该fragment对应的方法属性之类的。
修改 HelloPanel.controller.js
sap.ui.define([ "sap/ui/core/mvc/Controller", "sap/m/MessageToast", "sap/ui/core/Fragment" ], function (Controller, MessageToast, Fragment) { "use strict"; return Controller.extend("sap.ui.demo.walkthrough.controller.HelloPanel", { onShowHello : function () { … }, onOpenDialog : function () { var oView = this.getView(); // create dialog lazily if (!this.byId("helloDialog")) { // load asynchronous XML fragment Fragment.load({ id: oView.getId(), name: "sap.ui.demo.walkthrough.view.HelloDialog" }).then(function (oDialog) { // connect dialog to the root view of this component (models, lifecycle) oView.addDependent(oDialog); oDialog.open(); }); } else { this.byId("helloDialog").open(); } } }); });
先通过this.byId("helloDialog")来获取这个对话框,如果不存在的话,那么就需要通过 sap.ui.xmlfragment 来对它进行实例化。他有着这些参数:
id: 视图HelloPanel的ID,用于为fragment加上前缀,在这里,为对话框控件定义了ID helloDialog,可以通过调用oView.byId(“helloDialog”)通过view访问dialog。
这确保即使以相同的方式在其他view中实例化相同的fragment,每个dialog都有其惟一的ID,该ID由view ID和dialog ID连接而成。
如果有相同的id,那么框架会报错。
.then(function (oDialog) 其中的oDialog为返回的DIalog控件。
oView.addDependent(oDialog); 我们将对话框添加为Dependent,依赖于要连接到视图模型生命周期的视图。当视图被销毁时,对话框将自动销毁。否则,需要销毁对话框以释放其资源。
始终使用addDependent方法将对话框连接到视图的生命周期管理和数据绑定。
私有函数和变量总是以下划线开头。
17 Step 17: Fragment Callbacks
为dialog添加事件。
修改HelloPanel.controller.js
sap.ui.define([ "sap/ui/core/mvc/Controller", "sap/m/MessageToast", "sap/ui/core/Fragment" ], function (Controller, MessageToast, Fragment) { "use strict"; return Controller.extend("sap.ui.demo.walkthrough.controller.HelloPanel", { onShowHello : function () { // read msg from i18n model var oBundle = this.getView().getModel("i18n").getResourceBundle(); var sRecipient = this.getView().getModel().getProperty("/recipient/name"); var sMsg = oBundle.getText("helloMsg", [sRecipient]); // show message MessageToast.show(sMsg); }, onOpenDialog : function () { var oView = this.getView(); // create dialog lazily if (!this.byId("helloDialog")) { // load asynchronous XML fragment Fragment.load({ id: oView.getId(), name: "sap.ui.demo.walkthrough.view.HelloDialog", controller: this }).then(function (oDialog) { // connect dialog to the root view of this component (models, lifecycle) oView.addDependent(oDialog); oDialog.open(); }); } else { this.byId("helloDialog").open(); } }, onCloseDialog : function () { this.byId("helloDialog").close(); } }); });
fragment没有controller,controller这个参数是可选的,它允许将该引用传递给对象,他可以是任何对象,不一定是controller,这里将dialog的引用传递给HelloPanel controller。
onCloseDialog被放入同一个controller中,通过调用dialog的内部函数来关闭对话框。
修改 HelloDialog.fragment.xml
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" > <Dialog id="helloDialog" title ="Hello {/recipient/name}"> <beginButton> <Button text="{i18n>dialogCloseButtonText}" press=".onCloseDialog"/> </beginButton> </Dialog> </core:FragmentDefinition>
在fragment中,我们在Dialog的聚合beginButton中,添加了一个按钮,并给其分配了一个事件onCloseDialog,当按钮摁下时,就会触发HelloPanel controller中的函数,来关闭该窗口。
Dialog名为beginButton与endButton的aggregation,将button放在这两个aggregation中可以保证beginButton在endButton的前方。
如果文本是从左至右,那么按钮也是从左至右,如果文本是从右至左,那么按钮也是从右至左。
修改i18n.properties
# App Descriptor appTitle=Hello World appDescription=A simple walkthrough app that explains the most important concepts of SAPUI5 # Hello Panel showHelloButtonText=Say Hello helloMsg=Hello {0} homePageTitle=Walkthrough helloPanelTitle=Hello World openDialogButtonText=Say Hello With Dialog dialogCloseButtonText=Ok
18 Step 18: Icons
修改HelloPanel.view.xml
<mvc:View controllerName="sap.ui.demo.walkthrough.controller.HelloPanel" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Panel headerText="{i18n>helloPanelTitle}" class="sapUiResponsiveMargin" width="auto" > <content> <Button id="helloDialogButton" icon="sap-icon://world" text="{i18n>openDialogButtonText}" press=".onOpenDialog" class="sapUiSmallMarginEnd"/> <Button text="{i18n>showHelloButtonText}" press=".onShowHello" class="myCustomButton"/> <Input value="{/recipient/name}" valueLiveUpdate="true" width="60%"/> <FormattedText htmlText="Hello {/recipient/name}" class="sapUiSmallMargin sapThemeHighlight-asColor myCustomText"/> </content> </Panel> </mvc:View>
为button追加了一个icon,icon需要使用"sap-icon://"的规则来标示图标。
可以访问https://sapui5.hana.ondemand.com/test-resources/sap/m/demokit/iconExplorer/webapp/index.html来选择图标。
修改HelloDialog.fragment.xml
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" > <Dialog id="helloDialog" title ="Hello {/recipient/name}"> <content> <core:Icon src="sap-icon://hello-world" size="8rem" class="sapUiMediumMargin"/> </content> <beginButton> <Button text="{i18n>dialogCloseButtonText}" press=".onCloseDialog"/> </beginButton> </Dialog> </core:FragmentDefinition>
在Dialog中加入一个Icon的control,并放入Dialog的aggregation content中。
19 Step 19: Reuse Dialogs
之前实装的Dialog并没有跨视图重用,因为我们将打开Dialog与关闭Dialog的方法放在了HelloPanel这个controller中了。如果使用这种方法,需要将打开Dialog与关闭Dialog的代码放到每个视图的控制器中。
所以我们需要在component级别上调用Dialog。
修改Component.js
sap.ui.define([ "sap/ui/core/UIComponent", "sap/ui/model/json/JSONModel", "./controller/HelloDialog" ], function (UIComponent, JSONModel, HelloDialog) { "use strict"; return UIComponent.extend("sap.ui.demo.walkthrough.Component", { metadata : { manifest : "json" }, init : function () { // call the init function of the parent UIComponent.prototype.init.apply(this, arguments); // set data model var oData = { recipient : { name : "World" } }; var oModel = new JSONModel(oData); this.setModel(oModel); // set dialog this._helloDialog = new HelloDialog(this.getRootControl()); }, exit : function() { this._helloDialog.destroy(); delete this._helloDialog; }, openHelloDialog : function () { this._helloDialog.open(); } }); });
this._helloDialog = new HelloDialog(this.getRootControl());
执行HelloDialog中的构造方法constructor。
对话框被实例化成一个新的对象,并被保存在component的私有属性中。我们需要将跟视图的实例传递给构造函数,因为需要将Dialog与根视图的生命周期进行连接。
可以通过查看manifest.json文件中的参数rootView来确定根视图,这里根视图是sap.ui.demo.walkthrough.view.App。
openHelloDialog函数,调用dialog对象的open方法。
exit函数为一个钩子函数,sapui5在销毁组件时调用exit的函数,这里销毁dialog对象。
新建HelloDialog.js
sap.ui.define([ "sap/ui/base/ManagedObject", "sap/ui/core/Fragment" ], function (ManagedObject, Fragment) { "use strict"; return ManagedObject.extend("sap.ui.demo.walkthrough.controller.HelloDialog", { constructor : function (oView) { this._oView = oView; }, exit : function () { delete this._oView; }, open : function () { var oView = this._oView; // create dialog lazily if (!oView.byId("helloDialog")) { var oFragmentController = { onCloseDialog : function () { oView.byId("helloDialog").close(); } }; // load asynchronous XML fragment Fragment.load({ id: oView.getId(), name: "sap.ui.demo.walkthrough.view.HelloDialog", controller: oFragmentController }).then(function (oDialog) { // connect dialog to the root view of this component (models, lifecycle) oView.addDependent(oDialog); oDialog.open(); }); } else { oView.byId("helloDialog").open(); } } }); });
扩展sap.ui.base.ManagedObject 对象,来继承sapui5的核心功能。
这里没有传递一个controller作为第三个参数给Fragment,只传递给了一个定义在local的对象,用来执行onCloseDialog函数。
open方法实现Dialog的实例化,oView对象是sap.ui.demo.walkthrough.view.App,因为在component的init方法中,执行了执行HelloDialog中的构造方法constructor。
exit函数会被自动调用,用来释放内存。
修改HelloPanel.controller.js
sap.ui.define([ "sap/ui/core/mvc/Controller", "sap/m/MessageToast" ], function (Controller, MessageToast) { "use strict"; return Controller.extend("sap.ui.demo.walkthrough.controller.HelloPanel", { onShowHello : function () { // read msg from i18n model var oBundle = this.getView().getModel("i18n").getResourceBundle(); var sRecipient = this.getView().getModel().getProperty("/recipient/name"); var sMsg = oBundle.getText("helloMsg", [sRecipient]); // show message MessageToast.show(sMsg); }, onOpenDialog : function () { this.getOwnerComponent().openHelloDialog(); } }); });
调用getOwnerComponent访问来componet,并调用openHelloDialog函数将当前的视图与Dialog进行绑定。
修改App.view.xml
<mvc:View controllerName="sap.ui.demo.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Shell> <App class="myAppDemoWT"> <pages> <Page title="{i18n>homePageTitle}"> <headerContent> <Button icon="sap-icon://hello-world" press=".onOpenDialog"/> </headerContent> <content> <mvc:XMLView viewName="sap.ui.demo.walkthrough.view.HelloPanel"/> </content> </Page> </pages> </App> </Shell> </mvc:View>
追加一个按钮,以显示对话框的重用。
修改App.controller.js
sap.ui.define([ "sap/ui/core/mvc/Controller" ], function (Controller) { "use strict"; return Controller.extend("sap.ui.demo.walkthrough.controller.App", { onOpenDialog : function () { this.getOwnerComponent().openHelloDialog(); } }); });
添加函数用来打开Dialog。
20 Step 20: Aggregation Binding
将json数据绑定在页面上。
新建Invoices.json
{ "Invoices": [ { "ProductName": "Pineapple", "Quantity": 21, "ExtendedPrice": 87.2000, "ShipperName": "Fun Inc.", "ShippedDate": "2015-04-01T00:00:00", "Status": "A" }, { "ProductName": "Milk", "Quantity": 4, "ExtendedPrice": 9.99999, "ShipperName": "ACME", "ShippedDate": "2015-02-18T00:00:00", "Status": "B" }, { "ProductName": "Canned Beans", "Quantity": 3, "ExtendedPrice": 6.85000, "ShipperName": "ACME", "ShippedDate": "2015-03-02T00:00:00", "Status": "B" }, { "ProductName": "Salad", "Quantity": 2, "ExtendedPrice": 8.8000, "ShipperName": "ACME", "ShippedDate": "2015-04-12T00:00:00", "Status": "C" }, { "ProductName": "Bread", "Quantity": 1, "ExtendedPrice": 2.71212, "ShipperName": "Fun Inc.", "ShippedDate": "2015-01-27T00:00:00", "Status": "A" } ] }
修改manifest.json
{ … "sap.ui5": { "rootView": "sap.ui.demo.walkthrough.view.App", […] "models": { "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { "bundleName": "sap.ui.demo.walkthrough.i18n.i18n" } }, "invoice": { "type": "sap.ui.model.json.JSONModel", "uri": "Invoices.json" } } } }
新添加了一个model invoice,因为是一个json数据,所以设置成JSONModel的type,uri是相对于component的路径,通过这个配置,component会自动实例化一个JSONModel,将丛 Invoices.json文件中加载数据。
最后将实例化的JSONModel命名为invoice model放到组件上。这个被命名的model,在整个app中都是可见的。
修改App.view.xml
<mvc:View controllerName="sap.ui.demo.walkthrough.controller.App" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true"> <Shell> <App class="myAppDemoWT"> <pages> <Page title="{i18n>homePageTitle}"> <headerContent> <Button icon="sap-icon://hello-world" press=".onOpenDialog"/> </headerContent> <content> <mvc:XMLView viewName="sap.ui.demo.walkthrough.view.HelloPanel"/> <mvc:XMLView viewName="sap.ui.demo.walkthrough.view.InvoiceList"/> </content> </Page> </pages> </App> </Shell> </mvc:View>
新建InvoiceList.view.xml
<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <List headerText="{i18n>invoiceListTitle}" class="sapUiResponsiveMargin" width="auto" items="{invoice>/Invoices}" > <items> <ObjectListItem title="{invoice>Quantity} x {invoice>ProductName}"/> </items> </List> </mvc:View>
在这个新的view中,会显示一个list的控件,在list的aggregation item中,为其绑定json数据的根路径Invoices,由于我们为model进行了命名,所以在每个绑定之前都要加上"invoice>"。
在aggregation items中,定义了一个模板,将自动地放入json数据。更准确的说,是使用了ObjectListItem为items aggregation创建子控件。
将单个invoice的一些属性绑定到tltle上,这里使用一个相对路径不包含"/"。由于我们使用了items={invoice>/ invoice}将invoices绑定到了控件,所以我们可以进行访问。
修改i18n.properties
# App Descriptor appTitle=Hello World appDescription=A simple walkthrough app that explains the most important concepts of SAPUI5 # Hello Panel showHelloButtonText=Say Hello helloMsg=Hello {0} homePageTitle=Walkthrough helloPanelTitle=Hello World openDialogButtonText=Say Hello With Dialog dialogCloseButtonText=Ok # Invoice List invoiceListTitle=Invoices
将后台数据放入JSONModel
oModel.read("/DocumentSet/", { async: false, filters: aFilter, success: function (oERP) { that.fHideBusyIndicator(); if (oERP.results[0].MSGTY == "E") { that.fShowMessageBox('error', oERP.results[0].MSGCT); that.getView().byId("table").setModel(new JSONModel([])); that.getView().setModel(new JSONModel()); return; } else if (oERP.results[0].MSGTY == "S") { sCount = oERP.results.length; //Inner table search field for (var i in oERP.results) { var posnr = oERP.results[i].POSNR; var matnr = oERP.results[i].MATNR; var maktx = oERP.results[i].MAKTX; var menge = oERP.results[i].MENGE; var meins = oERP.results[i].MEINS; var kostl = oERP.results[i].KOSTL; var grund = oERP.results[i].GRUND; var zcomm = oERP.results[i].ZCOMM; var lfdat = oERP.results[i].LFDAT; var total = oERP.results[i].TOTAL; oERP.results[i].filter = posnr + matnr + maktx + menge + meins + kostl + grund + zcomm + lfdat + total; } var oTable = that.getView().byId('table'); var oModel = new JSONModel(oERP); oTable.setModel(oModel); } }, error: function (oError) { that.fHideBusyIndicator(); that.getView().setModel(new JSONModel()); that.fShowMessageBox('error', oError.message); } });
来源:https://www.cnblogs.com/suoluo119/p/11510349.html