1
votes

Context

I'm creating a little demo page that displays some straight forward functionality of UI5. This page consists of two main pages:

  • On the first page, there's a list of carriers which can be created, deleted, and updated. These carriers have an ID (Carrid).
  • If one clicks a carrier, they get routed to the second page on which all the flights of the selected carrier are shown in a table (with some information about the flights).

The table looks like this:

<Table id="detailTable" inset="false" class="sapUiResponsiveMargin">
    <columns>
        <Column>
            <Text text="ID" />
        </Column>
        <Column>
            <Text text="Flightnumber" />
        </Column>
        <Column>
            <Text text="Starts in" />
        </Column>
        <Column>
            <Text text="Departs at" />   
        </Column> 
        <Column>
            <Text text="Lands in" />   
        </Column> 
        <Column>
            <Text text="Lands at" />   
        </Column>
    </columns>
</Table>

The data is bound to the columns with this code:

// Get routing data and show only entrys with the matched primary key (Carrid)
_onRouteMatched: function(oEvent) {
    // ...
    var oArgs = oEvent.getParameter("arguments");
    var oFlightTable = oView.byId("detailTable");
    oFlightTable.bindAggregation("items", {
        path: "/CarrierSet(" + "'" + oArgs.flightPath + "'" + ")/FlightSet",
        template: new sap.m.ColumnListItem({
            cells: [
                new sap.m.Text({
                    text: "{Carrid}"
                }),
                new sap.m.Text({
                    text: "{Connid}"
                }),
                new sap.m.Text({
                    text: "{Cityfrom}"
                }),
                new sap.m.Text({
                    text: "{Deptime}"
                }),
                new sap.m.Text({
                    text: "{Cityto}"
                }),
                new sap.m.Text({
                    text: "{Arrtime}"
                })
            ]
        })
    });
}

Problem

The code works fine if the data can be shown without manipulating it first. But the fields {Deptime} and {Arrtime} have the type Edm.Time which I need to convert first in order to display it in a human readable form.
I was able to achieve this with this bit of code (I know, not the most efficient way, but im still learning. So if you have any improvements, feel free to post them):

pageTable.addEventDelegate({
    onAfterRendering: function() {
        var mTable = this.getView("FilterBarSimple").byId("detailTable");
        var mModel = mTable.getModel();
        var aItems = mTable.getItems();

        // ----- TIME CONVERSION ----

        var arrayTime = [];
        for (var iTime = 0; iTime < aItems.length; iTime++) {
            var iAdded = mModel.getProperty("Deptime", aItems[iTime].getBindingContext());
            arrayTime.push(iAdded);
        }
        var timeFormat = sap.ui.core.format.DateFormat.getTimeInstance({
            pattern: "kk:mm:ss"
        });
        var tz = new Date(0).getTimezoneOffset() * 60 * 1000;
        var arrayTimeClean = [];
        $.each(arrayTime, function(ii, ee) {
            var timeStr = timeFormat.format(new Date(ee.ms + tz));
            arrayTimeClean.push(timeStr);
        });
    }
});

This generates this output which is correct:
Image_Of_Converted_Output

But I'm not able to correctly bind this manipulated data into the table again. I've tried it with the OData.read() function and some other rather hacky approaches but I was never successful and I'm stuck with this problem for quite some time now.

If anyone has an idea or a suggestion, I'd be more than thankful if you let me know.

1

1 Answers

9
votes

There is no need for "hacky approaches" or custom formatters in case you simply want to display the time (or date) in a human readable form. UI5 comes with the concept data typesdoc which has the following advantages:

  • Let UI5 format, parse, and even validate the value for you.
  • Supports two-way data binding in contrast to formatter.
  • Additional format options or input constraints can be defined.

In our case, the appropriate type for displaying the value of Edm.Time is sap.ui.model.odata.type.Time.api

Sample

From https://embed.plnkr.co/F3t6gI8TPUZwCOnA:

<Table items="{carrierFlights}"
  xmlns="sap.m"
  xmlns:core="sap.ui.core"
  core:require="{
    DateTimeType: 'sap/ui/model/odata/type/DateTime',
    TimeType: 'sap/ui/model/odata/type/Time'
  }"><!-- ... -->
  <ColumnListItem>
    <!-- Date only -->
    <Text text="{
      path: 'fldate',
      type: 'DateTimeType',
      constraints: {
        displayFormat: 'Date'
      }
    }" />
    <!-- Time only -->
    <Text text="{
      path: 'departureTime',
      type: 'TimeType',
      formatOptions: { style: 'long' }
    }" />
    <!-- works with any other controls such as DatePicker, TimePicker, etc.. -->
  </ColumnListItem>
</Table>

Note: About the core:require-syntax, see Require Modules in XML View and Fragment which is supported as of UI5 1.69. For lower versions, use the following syntax:

type: 'sap.ui.model.odata.type.(Date)Time'

Result

UI5 example

For more information, including how to bind DateTime or DateTimeOffset in DateRangeSelection, take a look at the documentation topic Date and Time Related Controls: Data Binding.


TL;DR

  1. Check which type the entity property is using in the service $metadata document.

  2. Use one of the OData types in the property binding:

    xmlns:core="sap.ui.core"
    core:require="{ RequiredODataType: 'sap/ui/model/odata/type/<appropriateType>' }"
    value="{
      path: 'myODataModel>myProperty',
      type: 'RequiredODataType',
      <Add formatOptions & constraints here depending on the required OData type>
    }"

    For a complete list of available OData types, see API Reference: sap.ui.model.odata.type.