SAPUI5 (29) - 使用 ViewSettingsDialog 实现排序分组和筛选

应用程序的筛选、排序和分组必不可少。为简化开发的工作量,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();
            }
        });
    });

源代码

29_odata_filter_sort_group_using_viewSettingsDialog

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

推荐阅读更多精彩内容