美文网首页
UI5_Walkthrough_3

UI5_Walkthrough_3

作者: LiuliuZhang | 来源:发表于2017-05-18 14:49 被阅读0次

    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后缀的文件,即为未经压缩的源文件

    相关文章

      网友评论

          本文标题:UI5_Walkthrough_3

          本文链接:https://www.haomeiwen.com/subject/xzylxxtx.html