Sort table by certain parts of string only

2019-06-07 00:29发布

问题:

The sorting works basically fine using the sorter. One column is the full name (e.g. "Steve Jobs"). I have only the full name in that entity set but I want to sort the entries by the last name (last word of the full name) when clicking the full name column header. Is there some way to do this?

回答1:

You'll need to define a custom comparator for the sorter which applies only if all the entities are available client-side, for example, by having the operationMode set to 'Client' when defining the OData list binding.API

sap.ui.getCore().attachInit(() => sap.ui.require([
  "sap/ui/model/odata/v2/ODataModel",
  "sap/ui/core/mvc/XMLView",
  "sap/ui/model/json/JSONModel",
  "sap/ui/model/Sorter",
], (ODataModel, XMLView, JSONModel, Sorter) => {
  "use strict";
  const odataModel = new ODataModel({
    serviceUrl: [
      "https://cors-anywhere.herokuapp.com/",
      "https://services.odata.org/V2/Northwind/Northwind.svc/",
    ].join(""),
    tokenHandling: false,
    preliminaryContext: true,
  });
  Promise.all([
    odataModel.metadataLoaded(),
    sap.ui.getCore().loadLibrary("sap.m", true),
  ]).then(() => XMLView.create({
    definition: `<mvc:View xmlns:mvc="sap.ui.core.mvc"
      xmlns="sap.m"
      xmlns:core="sap.ui.core"
      height="100%"
    >
      <App>
        <Page showHeader="false">
          <Table id="myResponsiveTable"
            items="{
              path: '/Customers',
              parameters: {
                select: 'CustomerID, ContactName',
                operationMode: 'Client'
              }
            }"
          >
            <columns>
              <Column id="customerIdColumn"
                sortIndicator="{colCustomerId>/sortOrder}"
                width="33%"
              >
                <Text text="Customer ID">
                  <customData>
                    <core:CustomData
                      key="sorterPath"
                      value="CustomerID"
                    />
                  </customData>
                </Text>
              </Column>
              <Column id="fullNameColumn"
                sortIndicator="{colFullName>/sortOrder}"
                width="auto"
              >
                <Text text="Full Name">
                  <customData>
                    <core:CustomData
                      key="sorterPath"
                      value="ContactName"
                    />
                  </customData>
                </Text>
              </Column>
            </columns>
            <ColumnListItem>
              <Text text="{CustomerID}" />
              <Text text="{ContactName}" />
            </ColumnListItem>
          </Table>
        </Page>
      </App>
    </mvc:View>`,
    afterInit: function() { // === onInit
      const table = this.byId("myResponsiveTable");
      activateColumnPress(table, onColumnPress);
    },
    models: {
      undefined: odataModel,
      colCustomerId: new JSONModel({ sortOrder: "None" }),
      colFullName: new JSONModel({ sortOrder: "None" }),
    }
  }).then(view => view.placeAt("content")));

  function activateColumnPress(table, handler) {
    // Making columns clickable for the demo
    table.bActiveHeaders = true;
    table.onColumnPress = col => handler(table, col);
  }
  
  function onColumnPress(table, pressedCol) {
    table.getColumns()
      .filter(col => !(col.getSortIndicator() === pressedCol.getSortIndicator()))
      .map(col => col.setSortIndicator("None"));
    table.getBinding("items").sort(createSorter(pressedCol));
  }

  function createSorter(column) {
    return column.getHeader().data("sorterPath") === "ContactName"
      ? createFullNameSorter(column, toggleSort(column.getModel("colFullName")))
      : createCustomerIdSorter(column, toggleSort(column.getModel("colCustomerId")));
  }

  function toggleSort(colModel) {
    const descending = colModel.getProperty("/sortOrder") !== "Ascending";
    colModel.setProperty("/sortOrder", descending ? "Ascending" : "Descending");
    return !descending;
  }

  function createFullNameSorter(column, descending) {
    const comparator = (a, b) => a.split(" ").pop().localeCompare(b.split(" ").pop());
    return new Sorter("ContactName", descending, false, comparator);
  }

  function createCustomerIdSorter(column, descending) {
    return new Sorter("CustomerID", descending);
  }

}));
<script id="sap-ui-bootstrap"
  src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
  data-sap-ui-libs="sap.ui.core"
  data-sap-ui-async="true"
  data-sap-ui-compatversion="edge"
  data-sap-ui-theme="sap_belize"
  data-sap-ui-xx-waitfortheme="true"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact" style="height: 100%;"></body>

Btw: the "Client" operation mode currently doesn't fetch all entities if the service has server-side paging implemented.

As you can see in the example above, the Sorter constructor can handle custom comparator which will be invoked when the sort method is called. For comparing last parts of the full names, you can define the comparator like this:

function compare(fullName_a, fullName_b) {
  const lastPart_a = fullName_a.split(" ").pop();
  const lastPart_b = fullName_b.split(" ").pop();
  return lastPart_a.localeCompare(lastPart_b); // 0 if equal. Otherwise a negative or positive number
}


标签: sapui5