应用程序的筛选、排序和分组必不可少。为简化开发的工作量,SAPUI5 做了几个通用控件,包括 OpenUI5 的 sap.m.ViewSettingsDialog
和 SAPUI5 的 Smart Filter Toolbar (只在 SAPUI5 中, OpenUI5 中没有)。基本上,sap.m.ViewSettingsDialog
能够满足常规需求。本篇就介绍 ViewSettingsDialog
如何帮助在 UI 中实现数据的筛选、排序和分组。
应用的界面如下:
当点击这个按钮,弹出对话框。第一个界面是排序,可以按照 Table
的所有字段,进行升序或降序排序。
点击切换到筛选,我们设置为允许按照【城市】进行筛选:
点击城市,可以看到涉及的所有城市,允许勾选:
切换到分组,设置为按【国家】进行分组:
应用代码的结构:
index.html
创建一个 sap.m.App
的实例, App
包含一个 xmlView
的实例:
<!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"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-resourceroots='{"webapp": "./"}'
data-sap-ui-theme="sap_bluecrystal">
</script>
<script>
var oApp = new sap.m.App({
pages: [sap.ui.xmlview("appView", "webapp.view.Table")]
});
oApp.placeAt("content");
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content"></div>
</body>
</html>
Table.view.xml
这是一个 View 文件,用于展示界面。View 中包含一个 Table,有【供应商ID】,【供应商名称】,【地址】,【城市】和【国家】五列。绑定到 Suppliers
:
<core:View xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
controllerName="webapp.controller.Table"
xmlns:html="http://www.w3.org/1999/xhtml">
<Page title="排序,分组和筛选">
<content>
<Table items="{/Suppliers}" id="idTable" inset="true">
<headerToolbar>
<Toolbar>
<Title level="H2" text="供应商清单" />
<ToolbarSpacer />
<Button press="onTableSettings"
icon="sap-icon://drop-down-list" />
</Toolbar>
</headerToolbar>
<columns>
<Column id="SupplierID">
<Text text="供应商ID" />
</Column>
<Column id="CompanyName">
<Text text="供应商名称" />
</Column>
<Column id="Address">
<Text text="地址" />
</Column>
<Column id="City">
<Text text="城市" />
</Column>
<Column id="Country">
<Text text="国家" />
</Column>
</columns>
<items>
<ColumnListItem >
<cells>
<ObjectIdentifier title="{SupplierID}" />
<Text text="{CompanyName}" />
<Text text="{Address}" />
<Text text="{City}" />
<Text text="{Country}" />
</cells>
</ColumnListItem>
</items>
</Table>
</content>
</Page>
</core:View>
SettingsDialog.fragment.xml
这是一个 OpenUI5 的 Fragement 文件。新建的时候,新建一个文件,然后输入下面的内容。
<core:FragmentDefinition xmlns:core="sap.ui.core" xmlns="sap.m">
<ViewSettingsDialog confirm="onConfirm">
<sortItems>
<ViewSettingsItem selected="true" key="CompanyName" text="供应商名称" />
<ViewSettingsItem key="City" text="城市" />
</sortItems>
<groupItems>
<ViewSettingsItem key="Country" text="国家"/>
</groupItems>
<filterItems>
<ViewSettingsFilterItem text="城市" key="City">
<items>
<ViewSettingsItem key="City" text="Tokyo"/>
<ViewSettingsItem key="City" text="London"/>
<ViewSettingsItem key="City" text="Manchester"/>
</items>
</ViewSettingsFilterItem>
</filterItems>
</ViewSettingsDialog>
</core:FragmentDefinition>
主要是申明一个 sap.m.ViewSettingsDialog
, 其中包括 sortItems
(排序项),groupItems
(分组项) 和 filterItems
(筛选项)。对这些些项,我们先用用硬编码的方式,后面再来通用化。比如,现在筛选时,目前界面只出现 Tykyo, London 和 Manchester 三个城市,后面根据 Table
中的数据中涉及的城市,全部出现在筛选项中。
Table.controller.js
主要的控制逻辑都在控制器代码中,先给出完整代码:
sap.ui.define(["sap/ui/core/mvc/Controller",
"sap/ui/model/odata/v2/ODataModel",
"sap/ui/model/json/JSONModel",
"sap/ui/model/Sorter",
"sap/ui/model/Filter"],
function (Controller, ODataModel, JSONModel, Sorter, Filter) {
"use strict";
return Controller.extend("webapp.controller.Table", {
// -------------------------------
// Initialization event
// -------------------------------
onInit: function () {
// Application model
var sServiceUrl = "https://cors-anywhere.herokuapp.com/"
+ "http://services.odata.org/V3/Northwind/Northwind.svc/";
var oModel = new ODataModel(sServiceUrl);
oModel.setUseBatch(false);
this.getView().setModel(oModel);
},
// ---------------------------------------------
// 设置 Table 的 排序,分组和筛选
// ---------------------------------------------
onTableSettings: function (oEvent) {
var oDialog = this.getView().byId("SettingsDialog");
if (!oDialog) {
oDialog = sap.ui.xmlfragment("webapp.view.SettingsDialog", this);
}
oDialog.open();
},
onConfirm: function (oEvent) {
var oBinding = this.getView().byId("idTable").getBinding("items");
var mParams = oEvent.getParameters();
// Apply grouping
var aSorters = [];
if (mParams.groupItem) {
var sGroupKey = mParams.groupItem.getKey();
var bDescending = mParams.groupDescending;
aSorters.push(new Sorter(sGroupKey, bDescending, true));
}
// Apply sorter
if (mParams.sortItem) {
var sSortKey = mParams.sortItem.getKey();
var bDescending = mParams.sortDescending;
aSorters.push(new Sorter(sSortKey, bDescending));
}
oBinding.sort(aSorters);
// Apply filters
var aFilters = [];
if (mParams.filterItems) {
var count = mParams.filterItems.length;
for (var i = 0; i < count; i++) {
var oFilterItem = mParams.filterItems[i];
var oFilter = new Filter(oFilterItem.getKey(),
sap.ui.model.FilterOperator.EQ, oFilterItem.getText());
aFilters.push(oFilter);
}
}
oBinding.filter(aFilters);
} // end of onConfirm
});
});
代码说明:
-
onInit
事件处理函数,实例化oDataModel
并绑定到服务器端数据,设置当前的 View 所用的 Model 为这个oDataModel
。 -
分组:
var aSorters = [];
if (mParams.groupItem) {
var sGroupKey = mParams.groupItem.getKey();
var bDescending = mParams.groupDescending;
aSorters.push(new Sorter(sGroupKey, bDescending, true));
}
var oBinding = this.getView().byId("idTable").getBinding("items");
oBinding.sort(aSorters);
- 排序:
if (mParams.sortItem) {
var sSortKey = mParams.sortItem.getKey();
var bDescending = mParams.sortDescending;
aSorters.push(new Sorter(sSortKey, bDescending));
}
var oBinding = this.getView().byId("idTable").getBinding("items");
oBinding.sort(aSorters);
- 筛选:
var aFilters = [];
if (mParams.filterItems) {
var count = mParams.filterItems.length;
for (var i = 0; i < count; i++) {
var oFilterItem = mParams.filterItems[i];
var oFilter = new Filter(oFilterItem.getKey(),
sap.ui.model.FilterOperator.EQ, oFilterItem.getText());
aFilters.push(oFilter);
}
}
var oBinding = this.getView().byId("idTable").getBinding("items");
oBinding.filter(aFilters);
实现按 Table 的所有字段排序
上面 Controller
对筛选、排序和分组,代码基本上实现了通用的代码。比如通过 var sGroupKey = mParams.groupItem.getKey();
获取 Group item
的 Key, 通过 var bDescending = mParams.groupDescending;
获取是否按降序排列。 但 Table
中有多个字段,为了实现灵活性,通过代码将所有字段加载到 Sort item
中:
首先获得 Table
的所有 Headers
, 包括 id 和 header text:
_getColumnHeaders: function(){
var aColumnHeaders = [];
var aColumns = this.getView().byId("idTable").getColumns();
for (var i = 0; i < aColumns.length; i++){
var sColumnID = aColumns[i].sId;
var sHeaderText = aColumns[i].getHeader().getText();;
// ID 中包含 view 的信息,分解得到字段的 id
var aID = sColumnID.split('--');
aColumnHeaders.push({
key: aID[1],
text: sHeaderText
});
}
return aColumnHeaders;
}
然后在 onTableSettings()
事件处理程序中将列增加到 Sort Item
:
onTableSettings: function (oEvent) {
var oDialog = this.getView().byId("SettingsDialog");
if (!oDialog) {
oDialog = sap.ui.xmlfragment("webapp.view.SettingsDialog", this);
}
// 增加 sort item
var aColumnHeaders = this._getColumnHeaders();
oDialog.destroySortItems();
for (var i = 0; i < aColumnHeaders.length; i++){
oDialog.addSortItem(new sap.m.ViewSettingsItem({
key: aColumnHeaders[i].key,
text: aColumnHeaders[i].text
}));
}
oDialog.open();
}
从 Northwind 数据源中加载供应商的城市
为了实现动态的数据,从 Northwind 数据源中加载数据。使用 JSON Model:
_getCities: function(){
var aCities = [];
//var uniqueCities = [];
// 使用 JSON model
var sServiceUrl = "http://services.odata.org/V3/Northwind/Northwind.svc/Suppliers";
var oJSONModel = new JSONModel();
oJSONModel.loadData(sServiceUrl, null, false, "GET", false, false, null);
var oData = oJSONModel.getProperty("/value");
// 获取城市并且消除重复项
if (oData instanceof Array){
$.each(oData, function(i, element){
if ($.inArray(element.City, aCities) === -1) {
aCities.push(element.City);
}
});
}
return aCities.sort();
}
然后在 onTableSettings
事件处理程序中添加 Filter Item
:
onTableSettings: function (oEvent) {
var oDialog = this.getView().byId("SettingsDialog");
if (!oDialog) {
oDialog = sap.ui.xmlfragment("webapp.view.SettingsDialog", this);
}
// 增加 sort item
...
// 增加 filter items
var aSupplierCities = this._getCities();
var aFilterItems = [];
for (var i = 0; i < aSupplierCities.length; i++){
aFilterItems.push(
new sap.m.ViewSettingsItem({
text: aSupplierCities[i],
key: "City"
})
);
}
oDialog.destroyFilterItems();
oDialog.addFilterItem(new sap.m.ViewSettingsFilterItem({
key: "Filter_by_City",
text: "城市",
items: aFilterItems
}));
oDialog.open();
}
这样,就实现了动态加载供应商的城市。最后给出 Table.controller.js
重构后的完整代码。
sap.ui.define(["sap/ui/core/mvc/Controller",
"sap/ui/model/odata/v2/ODataModel",
"sap/ui/model/json/JSONModel",
"sap/ui/model/Sorter",
"sap/ui/model/Filter"],
function (Controller, ODataModel, JSONModel, Sorter, Filter) {
"use strict";
return Controller.extend("webapp.controller.Table", {
// -------------------------------
// Initialization event
// -------------------------------
onInit: function () {
// Application model
var sServiceUrl = "https://cors-anywhere.herokuapp.com/"
+ "http://services.odata.org/V3/Northwind/Northwind.svc/";
var oModel = new ODataModel(sServiceUrl);
oModel.setUseBatch(false);
this.getView().setModel(oModel);
},
// ---------------------------------------------
// 设置 Table 的 排序,分组和筛选
// ---------------------------------------------
onTableSettings: function (oEvent) {
var oDialog = this.getView().byId("SettingsDialog");
if (!oDialog) {
oDialog = sap.ui.xmlfragment("webapp.view.SettingsDialog", this);
}
// 增加 sort item
var aColumnHeaders = this._getColumnHeaders();
oDialog.destroySortItems();
for (var i = 0; i < aColumnHeaders.length; i++) {
oDialog.addSortItem(new sap.m.ViewSettingsItem({
key: aColumnHeaders[i].key,
text: aColumnHeaders[i].text
}));
}
// 增加 filter items
var aSupplierCities = this._getCities();
var aFilterItems = [];
for (var i = 0; i < aSupplierCities.length; i++) {
aFilterItems.push(
new sap.m.ViewSettingsItem({
text: aSupplierCities[i],
key: "City"
})
);
}
oDialog.destroyFilterItems();
oDialog.addFilterItem(new sap.m.ViewSettingsFilterItem({
key: "Filter_by_City",
text: "城市",
items: aFilterItems
}));
oDialog.open();
},
onConfirm: function (oEvent) {
var oBinding = this.getView().byId("idTable").getBinding("items");
var mParams = oEvent.getParameters();
// Apply grouping
var aSorters = [];
if (mParams.groupItem) {
var sGroupKey = mParams.groupItem.getKey();
var bDescending = mParams.groupDescending;
aSorters.push(new Sorter(sGroupKey, bDescending, true));
}
// Apply sorter
if (mParams.sortItem) {
var sSortKey = mParams.sortItem.getKey();
var bDescending = mParams.sortDescending;
aSorters.push(new Sorter(sSortKey, bDescending));
}
oBinding.sort(aSorters);
// Apply filters
var aFilters = [];
if (mParams.filterItems) {
var count = mParams.filterItems.length;
for (var i = 0; i < count; i++) {
var oFilterItem = mParams.filterItems[i];
var oFilter = new Filter(oFilterItem.getKey(),
sap.ui.model.FilterOperator.EQ, oFilterItem.getText());
aFilters.push(oFilter);
}
}
oBinding.filter(aFilters);
}, // end of onConfirm
_getColumnHeaders: function () {
var aColumnHeaders = [];
var aColumns = this.getView().byId("idTable").getColumns();
for (var i = 0; i < aColumns.length; i++) {
var sColumnID = aColumns[i].sId;
var sHeaderText = aColumns[i].getHeader().getText();
// ID 中包含 view 的信息,分解得到字段的 id
var aID = sColumnID.split('--');
aColumnHeaders.push({
key: aID[1],
text: sHeaderText
});
}
return aColumnHeaders;
}, // end of _getColumnHeaders
//-----------------------------------------------
// 从 OData 数据服务获取供应商的城市,并且消除重复项
//-----------------------------------------------
_getCities: function () {
var aCities = [];
//var uniqueCities = [];
// 使用 JSON model
var sServiceUrl = "http://services.odata.org/V3/Northwind/Northwind.svc/Suppliers";
var oJSONModel = new JSONModel();
oJSONModel.loadData(sServiceUrl, null, false, "GET", false, false, null);
var oData = oJSONModel.getProperty("/value");
// 获取城市并且消除重复项
if (oData instanceof Array) {
$.each(oData, function (i, element) {
if ($.inArray(element.City, aCities) === -1) {
aCities.push(element.City);
}
});
}
return aCities.sort();
}
});
});
网友评论