UI5_Walkthrough_3

2017-05-18  本文已影响0人  LiuliuZhang

Aggregation Binding

创建Invoices.json文件

{
  "Invoices": [
    {
      "ProductName": "Pineapple",
      "Quantity": 21,
      "ExtendedPrice": 87.2000,
      "ShipperName": "Fun Inc.",
      "ShippedDate": "2015-04-01T00:00:00",
      "Status": "A"
    },
    ......
  ]
}

将invoice添加到manifest.json的models中

      "invoice": {
        "type": "sap.ui.model.json.JSONModel",
        "uri": "Invoices.json"
      }

新建InvoiceList.view.xml,并在app view中通过<mvc:XMLView viewName="sap.ui.demo.wt.view.InvoiceList"/>绑定,添加List,items为invoice Model下/Invoices,items的title为Quantity x ProductName

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

Data Types

指定invoicelist的controller,在controller的onInit事件中,添加JSONModel{currency: "EUR"},并绑定到Model this.getView().setModel(oViewModel, "view");。在ObjectListItem中添加number与numberUnit属性,number使用Calculated Fields语法,type为sap.ui.model.type.Currency金额类型,需要两个parts,分别为金额和单位,在number属性中我们不显示单位,因此设置formatOptions: {showMeasure: false}

Expression Binding

在ObjectListItem中添加numberState属性,将其定义为三元表达式numberState="{= ${invoice>ExtendedPrice} > 50 ? 'Error' : 'Success' }"/>,表达式可以用{=expression}来表示,式中${invoice>ExtendedPrice}取出ExtendedPrice的值。

Custom Formatters

定义formatter.js模块,返回status text

sap.ui.define([], function () {
    "use strict";
    return {
        statusText: function (sStatus) {
            var resourceBundle = this.getView().getModel("i18n").getResourceBundle();
            switch (sStatus) {
                case "A":
                    return resourceBundle.getText("invoiceStatusA");
                case "B":
                    return resourceBundle.getText("invoiceStatusB");
                case "C":
                    return resourceBundle.getText("invoiceStatusC");
                default:
                    return sStatus;
            }
        }
    };
});

在InvoiceList controller中,引入formatter.js模块依赖,定义formatter事件formatter: formatter,在ObjectListItem中添加<firstStatus>标签,在ObjectStatus中定义formatter为'.formatter.statusText',表示当前controller下的formatter,并调用statusText

<ObjectStatus text="{
    path: 'invoice>Status',
    formatter: '.formatter.statusText'
}"/>

Filtering

给list一个idid="invoiceList",添加headertoolbar,加入搜索框,添加onFilterInvoices事件。

      <headerToolbar>
         <Toolbar>
            <Title text="{i18n>invoiceListTitle}"/>
            <ToolbarSpacer/>
            <SearchField width="50%" search="onFilterInvoices" selectOnFocus="false"/>
         </Toolbar>
      </headerToolbar>

在controller中添加Filter FilterOperator依赖,实现onFilterInvoices。SearchField触发事件后,将输入的值添加到query参数下,可以通过 oEvent.getParameter("query")得到输入的Search字段,创建一个Filter对象并将它push到aFilter数组中,Filter参数为path: ProductName,Operator:Contains,Value:sQuery。获取invoiceList的ListBinding对象,调用filter方法

        onFilterInvoices : function (oEvent) {
            // build filter array
            var aFilter = [];
            var sQuery = oEvent.getParameter("query");
            if (sQuery) {
                aFilter.push(new Filter("ProductName", FilterOperator.Contains, sQuery));
            }
            // filter binding
            var oList = this.getView().byId("invoiceList");
            var oBinding = oList.getBinding("items");
            oBinding.filter(aFilter);
        }

Sorting and Grouping

在items中定义sorter及group

items="{
            path : 'invoice>/Invoices',
            sorter : {
                path : 'ShipperName',
                group : true
            }

Remote OData Service

跨域请求配置
配置manifest.json,
在"sap.app"下添加dataSources

    "dataSources": {
      "invoiceRemote": {
        "uri": "https://services.odata.org/V2/Northwind/Northwind.svc/",
        "type": "OData",
        "settings": {
          "odataVersion": "2.0"
        }
      }
    }

invoice Model改成使用dataSource

      "invoice": {
        "dataSource": "invoiceRemote"
      }

在Eclipse中测试时,使用本地代理
将uri改为proxy/V2/Northwind/Northwind.svc/在web.xml中,SimpleProxyServlet下面添加如下配置,eclipse的Network connection需为Native或Direct

    <context-param>
        <param-name>com.sap.ui5.proxy.REMOTE_LOCATION</param-name>
        <param-value>http://services.odata.org</param-value>
    </context-param>

Mock Server Configuration

创建mockServer.html,在attachInit中,需要引入依赖,可以用sap.ui.require

sap.ui.require([
    "sap/ui/demo/wt/localService/mockserver",
    "sap/m/Shell",
    "sap/ui/core/ComponentContainer"
], function (mockserver, Shell, ComponentContainer) {
    mockserver.init();
    new Shell({
        app : new ComponentContainer({
            height: "100%",
            name: "sap.ui.demo.wt"
        })
    }).placeAt("content");
});

其中,mockserver.js模块的定义如下,其中,创建MockServer的rootUri需要匹配上manifest.json文件中的URI,MockServer.config进行全局配置。simulate方法传入Metadata的path及Mockdata的path,Metadata参考odata Metadata定义,Mockdata为json文件,通过start方法启动。

sap.ui.define([
    "sap/ui/core/util/MockServer"
], function (MockServer) {
    "use strict";
    return {
        init: function () {
            // create
            var oMockServer = new MockServer({
                rootUri: "/destinations/northwind/V2/Northwind/Northwind.svc/"
            }); 
            var oUriParameters = jQuery.sap.getUriParameters();
            // configure
            MockServer.config({
                autoRespond: true,
                autoRespondAfter: oUriParameters.get("serverDelay") || 1000
            });
            // simulate
            var sPath = jQuery.sap.getModulePath("sap.ui.demo.wt.localService");
            oMockServer.simulate(sPath + "/metadata.xml", sPath + "/mockdata");
            // start
            oMockServer.start();
        }
    };
});

Unit Test

测试前面创建的formatter.js模块,创建/test/unit/model/formatter.js,QUnit.module创建Module Formatting functions,beforeEach与afterEach事件中分别创建和销毁ResourceModel。

QUnit.module("Formatting functions", {
    beforeEach: function () {
        this._oResourceModel = new ResourceModel({
            bundleUrl : jQuery.sap.getModulePath("sap.ui.demo.wt", "/i18n/i18n.properties")
        });
    },
    afterEach: function () {
        this._oResourceModel.destroy();
    }
});

QUnit.test进行测试,测试名为Should return the translated texts,方法中,由于formatter中代码var resourceBundle = this.getView().getModel("i18n").getResourceBundle();我们不需要controller,view,model等功能,我们用SinonJS的stub方法来移除依赖,controller的getView方法返回view,我们这里this.stub()模拟controller,返回viewStub,oViewStub中,getModel返回ResourceModel,这里this.stub()模拟view,withArgs("i18n")模拟参数。然后将formatter.statusText绑定模拟的controller,此时代码中的this将指向ControllerStub。

QUnit.test("Should return the translated texts", function (assert) {
    // Arrange
    var oViewStub = {
        getModel: this.stub().withArgs("i18n").returns(this._oResourceModel)
    };
    var oControllerStub = {
        getView: this.stub().returns(oViewStub)
    };
    // System under test
    var fnIsolatedFormatter = formatter.statusText.bind(oControllerStub);
    // Assert
    assert.strictEqual(fnIsolatedFormatter("A"), "New", "The long text for status A is correct");
});

Integration Test with OPA

创建/test/integration/navigationJourney.js,引入opaQunit依赖,创建Navigation Module,创建opaTest,Given对象中调用准备function,本例中创建一个frame,When对象中调用配置的action,Then对象中进行判断。

sap.ui.require([
    "sap/ui/test/opaQunit"
], function () {
    "use strict";
    QUnit.module("Navigation");
    opaTest("Should open the hello dialog", function (Given, When, Then) {      
 Given.iStartMyAppInAFrame(jQuery.sap.getResourcePath("sap/ui/demo/app/test", ".html"));
        When.onTheAppPage.iPressTheSayHelloWithDialogButton();
        Then.onTheAppPage.iShouldSeeTheHelloDialog().
            and.iTeardownMyAppFrame();
    });
});

创建/test/integration/pages/App.js文件,createPageObjects创建Page对象onTheAppPage,添加actions与assertions,通过this.waitFor返回Promise对象,如下代码会寻找Button对象数组,aButtons[0]取第一个Button,.$()创建Jquery对象,并触发tap事件

return this.waitFor({
    controlType: "sap.m.Button",
    success: function (aButtons) {
        aButtons[0].$().trigger("tap");
    },
    errorMessage: "Did not find the helloDialogButton button on the app page"
});

Debug tool

在view中,把list中number改为错误的'invoice>ExTendedPrice',此时打开页面,Number没有值。
CTRL + ALT + SHIFT + S 打开SAPUI5 诊断工具,在control tree中,找到listitem,打开Binding Infos,可以看到number标记为invalid


有时候Debug不是那么容易,SAPUI5文件被优化成最小化版本,要进行深入的Debug源文件时,可以 CTRL + ALT + SHIFT + P 打开窗口,将Use Debug Sources 打上勾,再通过浏览器加载时,在F12开发者工具Network下有很多-dbg后缀的文件,即为未经压缩的源文件
上一篇下一篇

猜你喜欢

热点阅读