UI5_Walkthrough_3

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 文/Jack_lin(简书作者)原文链接:http://www.jianshu.com/p/5d2163640e2...
    笔笔请求阅读 535评论 0 0
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,119评论 29 470
  • Th丶小贺阅读 124评论 0 0