上次我們介紹了屬性綁定的妖。屬性綁定用于綁定單條數(shù)據(jù)绣檬。如果需要綁定多條數(shù)據(jù),則需要使用聚合綁定(aggregation binding)嫂粟,比如我們常見的ListBox, Combox或者表格娇未,都是含有多條數(shù)據(jù)的。概念比較容易理解星虹,關(guān)鍵是綁定的語法零抬。如果所有行都用同樣的方法顯示數(shù)據(jù),用template方法宽涌。什么是template方法呢平夜?就是各行的數(shù)據(jù)顯示方式應(yīng)該是固定的,像套用模板一樣卸亮。比如顯示供應(yīng)商信息忽妒,每一行的第一列是供應(yīng)商ID,第二列是供應(yīng)商名稱,都是固定的段直。熟悉ABAP的語言的讀者吃溅,可以根據(jù)ABAP內(nèi)表的line type來理解。
我們在前面用sap.ui.table.Table
顯示供應(yīng)商數(shù)據(jù)的時(shí)候坷牛,已經(jīng)有相應(yīng)的例子罕偎,請參考:SAPUI5 (08) - MVC的Model和數(shù)據(jù)綁定。 Template方式綁定有以下幾種方式:
- 使用settings設(shè)置
- 使用
sap.ui.base.ManagedObject
的bindAggregation()
方法 - 使用控件的類型化綁定方法
這三種方法本篇都會(huì)介紹京闰。如果想各行綁定的數(shù)據(jù)有變化,或者說是動(dòng)態(tài)的甩苛。比如在一個(gè)表格中蹂楣,有一列顯示讀者對某文章的點(diǎn)擊次數(shù),當(dāng)點(diǎn)擊次數(shù)超過100時(shí)讯蒲,除了點(diǎn)擊次數(shù)痊土,還顯示熱門標(biāo)記,則可以使用factory function的方式來綁定墨林。后面也會(huì)給出示例赁酝。
本次使用sap.m.Table
控件顯示數(shù)據(jù),所以先介紹下sap.m.Table
的一些語法要點(diǎn)旭等。
sap.m.Table
sap.m.Table
control provides a set of sophisticated and convenience functions for responsive table design. To render the sap.m.Table properly, the order of the columns aggregation should match with the order of the items cells aggregation. Also sap.m.Table requires at least one visible sap.m.Column in columnsaggregation. For mobile devices, the recommended limit of table rows is 100 (based on 4 columns) to assure proper performance. To improve initial rendering on large tables, use the growing feature.
查看
sap.m.Table
從sap.m.ListBase
類繼承酌呆,用于顯示包含行和列的表格式數(shù)據(jù)。表格的列可以通過columns
聚合屬性來設(shè)置搔耕,也可以使用addColumn()
方法來添加隙袁。每一列都是sap.m.Column
對象。至少包含一個(gè)可見列弃榨。在一定設(shè)備上不要加載太多行菩收,以免影響性能。
sap.m.Table
的重要屬性:
-
columns
: 定義Table包含哪些列鲸睛,類型是sap.m.Column
數(shù)組娜饵。
另外,sap.m.Table
從sap.m.ListBase
繼承官辈,所以可以直接使用sap.m.ListBase
的屬性:
-
growing
: 設(shè)置Table顯示的數(shù)據(jù)可以依據(jù)向model的請求增加行 -
noDataText
: 當(dāng)Table沒有數(shù)據(jù)的時(shí)候顯示的文本箱舞,類型是string -
items
:sap.m.ListItemBase
數(shù)組,sap.m.ListItemBase類定義了列表項(xiàng)(list item)的基本特征钧萍。
sap.m.ColumnListItem
使用template方法顯示數(shù)據(jù)褐缠,每一行的template常用sap.m.ColumnListItem
,所以接下來介紹sap.m.ColumnListItem
的知識(shí)點(diǎn):
sap.m.ColumnListItem
can be used with the cells aggregation to create rows for thesap.m.Table
control. The columns aggregation of thesap.m.Table
should match with the cells aggregation.
查看
sap.m.ColumnListItem
用于創(chuàng)建sap.m.Table
的行风瘦,行中包含的cells需要與sap.m.Table
的Columns匹配队魏,順序一致。
本次將用到以下屬性:
-
vAlign
, 行的垂直對齊:- sap.ui.core.VerticalAlign.Bottom胡桨,底部對齊
- sap.ui.core.VerticalAlign.Inherit官帘,從父控件繼承
- [sap.ui.core.VerticalAlign.Middle, 居中對齊
- sap.ui.core.VerticalAlign.Top,頂部對齊
cells
: 行包含的cells昧谊,每一個(gè)cell都是sap.ui.core.Control
對象刽虹,從而開發(fā)人員可以根據(jù)需要選擇合適的控件,靈活度很高呢诬。
聚合綁定示例
和之前一樣涌哲,通過例子來加強(qiáng)理解。今天要實(shí)現(xiàn)的業(yè)務(wù)場景是在頁面中顯示一個(gè)文章列表尚镰,這些文章的閱讀次數(shù)阀圾,我們的要顯示的界面如下:
為了便于理解,先給出application area的完整代碼:
/**
* Aggregation binding
* Demo written by Stone Wang
*/
// application data
var oAppData = [
{ articleName: "SAP成本計(jì)算流程", type: "Locked", hits: 1048 },
{ articleName: "SAP物料價(jià)格修改", type: "Draft", hits: 58 },
{ articleName: "2017年SAP技術(shù)趨勢", type: "Unsaved", hits: 320},
{ articleName: "《人類簡史》讀后感", type: "Flagged", hits: 90 },
{ articleName: "《Core Java》第十版出版", type: "Favorite" , hits: 66}
];
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({ modelData: oAppData });
sap.ui.getCore().setModel(oModel);
// 定義一個(gè)包含包含3列的數(shù)組
var aColumns = [
new sap.m.Column({
header : new sap.m.Label({text : "文章"})
}),
new sap.m.Column({
header : new sap.m.Label({text : "標(biāo)記"})
}),
new sap.m.Column({
header : new sap.m.Label({text : "標(biāo)記"})
})
]
// 定義template, 每行包含3個(gè)cell
var oColumnListItem = new sap.m.ColumnListItem({
vAlign: "Middle",
cells: [
new sap.m.Text({text: "{articleName}"}),
new sap.m.ObjectMarker({type: "{type}"}),
new sap.m.ObjectMarker({
type: "{type}",
active: true,
press: function(oEvent){
sap.m.MessageToast.show(oEvent.getParameter("type") + " pressed");
}
})
]
});
// Table control
var oTable = new sap.m.Table({
columns : aColumns,
items: {path: "/modelData", template: oColumnListItem}
});
var oTablePanel = new sap.m.Panel({
headerText: "文章列表",
content: oTable
});
var oStandalonePanel = new sap.m.Panel("standalone-panel", {
headerText: "圖例:",
content: [
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Locked}),
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Flagged}),
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Favorite}),
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Draft}),
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Unsaved})
]
});
var oApp = new sap.m.App({ initialPage: "page" });
var oPage = new sap.m.Page("page", {
title:"Aggregation binding demo",
content: [oTablePanel, oStandalonePanel]
});
oApp.addPage(oPage).placeAt("content");
我們說明最主要的部分狗唉。因?yàn)門able包含三列初烘,所以我們先定義一個(gè)包含3列的數(shù)組,每一列都是sap.m.Column
對象分俯。
// 定義一個(gè)包含包含3列的數(shù)組
var aColumns = [
new sap.m.Column({
header : new sap.m.Label({text : "文章"})
}),
new sap.m.Column({
header : new sap.m.Label({text : "標(biāo)記"})
}),
new sap.m.Column({
header : new sap.m.Label({text : "標(biāo)記"})
})
]
剛才說過肾筐,對于每一行來說,都是一個(gè)template缸剪,我們使用ColumnListItem來代表template吗铐,每一行包含三個(gè)單元格,使用cells屬性表示橄登。每一個(gè)cell都是Control對象抓歼,我們使用sap.m.Text
顯示第一個(gè)單元格,綁定到articleName拢锹,使用sap.m.ObjectMarker
顯示第二個(gè)單元格和第三個(gè)單元格谣妻,第三個(gè)單元格與event handler綁定:
// 定義template, 每行包含3個(gè)cell
var oColumnListItem = new sap.m.ColumnListItem({
vAlign: "Middle",
cells: [
new sap.m.Text({text: "{articleName}"}),
new sap.m.ObjectMarker({type: "{type}"}),
new sap.m.ObjectMarker({
type: "{type}",
active: true,
press: function(oEvent){
sap.m.MessageToast.show(oEvent.getParameter("type") + " pressed");
}
})
]
});
最后定義sap.m.Table
對象,使用columns
聚合屬性和items
聚合屬性卒稳,items屬性實(shí)現(xiàn)的就是聚合綁定蹋半,當(dāng)然,需要ColumnListItem
的支持充坑。
// Table control
var oTable = new sap.m.Table({
columns : aColumns,
items: {path: "/modelData", template: oColumnListItem}
});
對Table的綁定减江,我們也可以使用bingItems方法來實(shí)現(xiàn):
var oTable = new sap.m.Table({
columns: aColumns
});
oTable.bindItems("/modelData", oColumnListItem);
或者:
var oTable = new sap.m.Table({
columns: aColumns
});
oTable.bindAggregation("items", "/modelData", oColumnListItem);
使用工廠函數(shù)實(shí)現(xiàn)聚合綁定
對上面的例子進(jìn)行重構(gòu),假設(shè)我們想顯示這些文章的閱讀次數(shù)捻爷,并且當(dāng)閱讀次數(shù)超過100時(shí)辈灼,就在閱讀次數(shù)下面加一個(gè)”熱門”字眼來標(biāo)識(shí)。也就是不同的單元格在顯示的時(shí)候是動(dòng)態(tài)的也榄。對這種動(dòng)態(tài)的數(shù)據(jù)顯示巡莹,就需要用factory function司志。如何做呢?我們使用sap.m.Table
的bindAggregation()
方法降宅,參數(shù)3使用匿名函數(shù)骂远,這個(gè)函數(shù)就是factory function:
// 使用Factory function實(shí)現(xiàn)動(dòng)態(tài)的數(shù)據(jù)顯示
oTable.bindAggregation("items", "/modelData", function(sId, oContext){
var oColumnListItem = new sap.m.ColumnListItem(sId, {vAlign: "Middle"});
oColumnListItem.addCell(new sap.m.Text({text: "{articleName}"}));
oColumnListItem.addCell(new sap.m.ObjectMarker({type: "{type}"}));
var oHits = oContext.getProperty("hits");
if (oHits >= 100) {
oColumnListItem.addCell(
new sap.ui.layout.VerticalLayout({
content: [
new sap.m.Text({text: "{hits}"}),
new sap.m.ObjectStatus({text:"熱門", state:"Success"})
]
})
)
} else {
oColumnListItem.addCell(
new sap.m.Text({text: "{hits}"})
)
}
return oColumnListItem;
});
注意Facotry 函數(shù)的參數(shù)必須是sId和oContext。如果點(diǎn)擊次數(shù)大于或等于100腰根,則cell中包括一個(gè)sap.m.Text
和一個(gè)sap.m.ObjectStatus
對象激才,垂直布局。如果點(diǎn)擊次數(shù)小于100额嘿,則只有一個(gè)sap.m.Text
來顯示瘸恼。函數(shù)最后需要使用return語句返回sap.m.ColumnListItem
對象。
貼上完整代碼:
/**
* Aggregation binding using factory function
* Demo written by Stone Wang
*/
// application data
var oAppData = [
{ articleName: "SAP成本計(jì)算流程", type: "Locked", hits: 1048 },
{ articleName: "SAP物料價(jià)格修改", type: "Draft", hits: 58 },
{ articleName: "2017年SAP技術(shù)方向", type: "Unsaved", hits: 320},
{ articleName: "《人類簡史》讀后感", type: "Flagged", hits: 90 },
{ articleName: "《Core Java》第十版出版", type: "Favorite" , hits: 66}
];
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({ modelData: oAppData });
sap.ui.getCore().setModel(oModel);
// 定義Column數(shù)組册养,包含3列
var aColumns = [
new sap.m.Column({
header : new sap.m.Label({text : "文章"})
}),
new sap.m.Column({
header : new sap.m.Label({text : "標(biāo)記"})
}),
new sap.m.Column({
header : new sap.m.Label({text: "閱讀次數(shù)"})
})
]
// Table control
var oTable = new sap.m.Table({
columns : aColumns
});
// 使用Factory function實(shí)現(xiàn)動(dòng)態(tài)的數(shù)據(jù)顯示
oTable.bindAggregation("items", "/modelData", function(sId, oContext){
var oColumnListItem = new sap.m.ColumnListItem(sId, {vAlign: "Middle"});
oColumnListItem.addCell(new sap.m.Text({text: "{articleName}"}));
oColumnListItem.addCell(new sap.m.ObjectMarker({type: "{type}"}));
var oHits = oContext.getProperty("hits");
if (oHits >= 100) {
oColumnListItem.addCell(
new sap.ui.layout.VerticalLayout({
content: [
new sap.m.Text({text: "{hits}"}),
new sap.m.ObjectStatus({text:"熱門", state:"Success"})
]
})
)
} else {
oColumnListItem.addCell(
new sap.m.Text({text: "{hits}"})
)
}
return oColumnListItem;
});
var oTablePanel = new sap.m.Panel({
headerText: "文章列表",
content: oTable
});
var oStandalonePanel = new sap.m.Panel("standalone-panel", {
headerText: "圖例:",
content: [
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Locked}),
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Flagged}),
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Favorite}),
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Draft}),
new sap.m.ObjectMarker({type: sap.m.ObjectMarkerType.Unsaved})
]
});
var oApp = new sap.m.App({ initialPage: "page" });
var oPage = new sap.m.Page("page", {
title:"Aggregation binding demo",
content: [oTablePanel, oStandalonePanel]
});
oApp.addPage(oPage).placeAt("content");
頁面顯示效果如下:
用xmlview實(shí)現(xiàn)factory方法的聚合綁定
xmlview是聲明式的钞脂,factory方式的聚合綁定卻是為了實(shí)現(xiàn)動(dòng)態(tài)的顯示。那么捕儒,如何在xmlview中實(shí)現(xiàn)動(dòng)態(tài)呢?要點(diǎn)如下:
1)xmlview中對需要?jiǎng)討B(tài)顯示的部分不作聲明
2)在controller中定義factory function邓夕,實(shí)現(xiàn)控件的綁定和動(dòng)態(tài)加載刘莹。
仍然用剛才的例子進(jìn)行重構(gòu),項(xiàng)目文件和路徑如下:
將數(shù)據(jù)放在json文件articles.json中焚刚,內(nèi)容:
[
{ "articleName": "SAP成本計(jì)算流程", "type": "Locked", "hits": 1048 },
{ "articleName": "SAP物料價(jià)格修改", "type": "Draft", "hits": 58 },
{ "articleName": "2017年SAP技術(shù)方向", "type": "Unsaved", "hits": 320},
{ "articleName": "《人類簡史》讀后感", "type": "Flagged", "hits": 90 },
{ "articleName": "《Core Java》第十版出版", "type": "Favorite" , "hits": 66}
]
index.html只有oApp
和oView点弯,
oApp`放在DIV中。
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
<script src="resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.m, sap.ui.layout"
data-sap-ui-resourceroots='{"bindingtest": "./binding_test"}'
data-sap-ui-theme="sap_bluecrystal">
</script>
<script>
var oApp = new sap.m.App({initialPage: "mainpage"});
var oView = sap.ui.xmlview({
id: "mainpage",
viewName: "bindingtest.view.aggregation_binding"
});
oApp.addPage(oView);
oApp.placeAt("content");
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content"></div>
</body>
</html>
aggregation_binding.view.xml:
<core:View xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
controllerName="bindingtest.controller.aggregation_binding"
xmlns:html="http://www.w3.org/1999/xhtml">
<Panel class="sapUiSmallMargin" headerText="文章列表">
<content>
<Table id="table" width="auto" class="sapUiSmallMargin"
noDataText="no data">
<columns>
<Column><header><Label text="文章" /></header></Column>
<Column><header><Label text="標(biāo)記" /></header></Column>
<Column hAlign="Right"><header><Label text="閱讀次數(shù)" /></header></Column>
</columns>
</Table>
</content>
</Panel>
<Panel class="sapUiSmallMargin" headerText="圖例">
<content>
<ObjectMarker class="sapUiSmallMargin" type="Locked" />
<ObjectMarker class="sapUiSmallMargin" type="Flagged" />
<ObjectMarker class="sapUiSmallMargin" type="Favorite" />
<ObjectMarker class="sapUiSmallMargin" type="Draft" />
<ObjectMarker class="sapUiSmallMargin" type="Unsaved" />
</content>
</Panel>
</core:View>
注意sap.m.Table只聲明了columns矿咕,沒有聲明items抢肛。items在代碼中實(shí)現(xiàn)。
aggregation_binding.controller.js:
sap.ui.define(["sap/ui/core/mvc/Controller"],
function(Controller){
"use strict";
// controller name
return Controller.extend("bindingtest.controller.aggregation_binding", {
//-------------------------------
// initialization
//-------------------------------
onInit: function() {
// binding view with model
var oModel = sap.ui.model.json.JSONModel();
oModel.loadData('binding_test/model/articles.json');
this.getView().setModel(oModel);
// Table object add items
var oTable = this.getView().byId("table");
oTable.bindItems({path: '/', factory: this.createCellsFactory});
},
//------------------------------------------------
// Factory function to add cells for table
//------------------------------------------------
createCellsFactory: function(sId, oContext) {
var oColumnListItem = new sap.m.ColumnListItem(sId, {vAlign: "Middle"});
// first two cells are not dynamic
oColumnListItem.addCell(new sap.m.Text({text: "{articleName}"}));
oColumnListItem.addCell(new sap.m.ObjectMarker({type: "{type}"}));
// third cell is dynamic
var oHits = oContext.getProperty("hits");
if (oHits >= 100) {
oColumnListItem.addCell(
new sap.ui.layout.VerticalLayout({
content: [
new sap.m.Text({text: "{hits}"}),
new sap.m.ObjectStatus({text:"熱門", state:"Success"})
]
})
)
} else {
oColumnListItem.addCell(
new sap.m.Text({text: "{hits}"})
)
}
return oColumnListItem;
} // end of createCellsFactory()
});
}
);
在onInit()中調(diào)用oTable的bindItems方法碳柱,bindItems方法包含factory方法: oTable.bindItems({path: '/', factory: this.createCellsFactory});