Skip to content

Formatter ​

You can format values like currencies, numerics, dates, or booleans directly on the frontend with UI5 type formatters.

UI5 formatter types use a special JSON-based binding syntax with these key elements:

  • parts: [...] — lists the model paths used as input (e.g., amount + currency)
  • type: '...' — the UI5 formatter type (e.g., sap.ui.model.type.Currency)
  • formatOptions: {...} — optional settings that control the output format
  • constraints: {...} — optional constraints applied when user input is parsed back

Note on ABAP syntax: inside string templates (|...|), escape the curly braces as \{ and \}, because { } normally denotes an embedded ABAP expression.

client->_bind_path( ) returns only the raw model path rather than the full binding expression (it is _bind( val = … path = abap_true ) under a readable name — see Binding), so you can embed it inside the parts array or a single-path path: entry. The path is e.g. /AMOUNT, unquoted — so the quotes around it are yours to write, and they have to be ' or ". A backtick is an ABAP string delimiter, not a UI5 one: written here it survives into the binding string, and UI5 answers with a syntax error and renders nothing at all.

For example, this ABAP code:

abap
|\{ parts: ['{ client->_bind_path( amount ) }'], type: 'sap.ui.model.type.Currency' \}|

produces this UI5 binding string at runtime:

text
{ parts: ['/AMOUNT'], type: 'sap.ui.model.type.Currency' }

The sections below show the binding-string pattern for each ABAP type that needs a formatter. Each pattern is the minimum that makes the value display and parse correctly — for runnable apps with full formatOptions, constraints, and read-only variants, see the samples repository.

Currency ​

ABAP p LENGTH n DECIMALS m + a c LENGTH 3 currency code (a plain string also works, as in the worked example below) → UI5 Currency formatter. Two parts entries; the type combines them into a locale-aware amount string:

abap
)->tag( `Input`
    )->a( n = `value` v = |\{ parts: [ '{ client->_bind_path( amount ) }',|
                       && | '{ client->_bind_path( currency ) }' ],|
                       && | type: 'sap.ui.model.type.Currency' \}|

Common formatOptions:

  • showMeasure: false — hides the currency, shows only the amount
  • showNumber: false — hides the amount, shows only the currency (UI5 1.89 and later)
  • preserveDecimals: false — rounds the amount to the currency's decimals; by default the type keeps any further decimals (UI5 1.89 and later — before, it always rounds)
  • currencyCode: false — shows the currency symbol (€) instead of the ISO code (EUR), where the currency has one
  • style: 'short' — compact notation (123M); 'long' formats a currency the same way

The Full Worked Example below demonstrates each of these variants in a single app.

Digit Sequence ​

ABAP n LENGTH n is sent as a digit string, leading zeros included. Without a type the zeros render literally. Use the OData String type with isDigitSequence: true:

abap
)->tag( `Text`
    )->a( n = `text` v = |\{ path: '{ client->_bind_path( numeric ) }',|
                      && | type: 'sap.ui.model.odata.type.String',|
                      && | constraints: \{ isDigitSequence: true \} \}|

This strips the leading zeros for display and re-pads them on write-back.

Date ​

ABAP d goes on the wire as an ISO date string, 2024-01-15 (an initial date as an empty string), and the framework reads the same shape back. For explicit locale or pattern control, use sap.ui.model.type.Date with a source pattern that matches the wire format:

abap
)->tag( `DatePicker`
    )->a( n = `value` v = |\{ path: '{ client->_bind_path( mv_date ) }',|
                       && | type: 'sap.ui.model.type.Date',|
                       && | formatOptions: \{ pattern: 'dd.MM.yyyy',|
                       && | source: \{ pattern: 'yyyy-MM-dd' \} \} \}|

source.pattern is the wire format (ABAP side); the outer pattern is what the user sees.

Time ​

ABAP t goes on the wire as 12:30:00 (an initial time as an empty string). Same pattern as Date, with sap.ui.model.type.Time:

abap
)->tag( `TimePicker`
    )->a( n = `value` v = |\{ path: '{ client->_bind_path( mv_time ) }',|
                       && | type: 'sap.ui.model.type.Time',|
                       && | formatOptions: \{ pattern: 'HH:mm',|
                       && | source: \{ pattern: 'HH:mm:ss' \} \} \}|

Boolean ​

A boolean needs no formatter. abap_bool is "X" or "" in ABAP, but it does not travel that way: the framework serializes the boolean ABAP types to a JSON true / false and converts back on the way in. So bind the attribute straight to the control and both directions work:

abap
)->tag( `CheckBox`
    )->a( n = `selected` v = client->_bind( mv_flag ) )

Inside a table row template, the same thing relative to the row:

abap
)->tag( `CheckBox`
    )->a( n = `selected` v = `{CHECKBOX}` )

It is the TYPE that decides, not the value

The mapping is keyed on the ABAP type: abap_bool, abap_boolean, xsdboolean, flag and xfeld become a JSON boolean. A flag you declared as c LENGTH 1 looks identical in the debugger and travels as the string"X" — a CheckBox bound to it stays unchecked, because "X" is not true. Type the attribute abap_bool and the problem disappears; that is the fix, not an expression binding.

An expression binding ({= ${/MV_FLAG} === 'X' }) is the wrong tool here twice over: it compares against a value that is not on the wire, and an expression binding cannot write back, so the box would not flip the attribute even if the comparison held.

A boolean written into the view is a different question

All of the above is about a bound value. An ABAP boolean put straight into the XML as an attribute value — )->a( n = visible v = xsdbool( … ) ) — is stringified to X or to an empty string (a bare v = flag does not even compile: v is a string), and UI5 reads a boolean attribute as true only when it says true: on 1.71 abap_true renders the control hidden, and a newer release logs X as invalid and ignores it, leaving the property at its default. Use the builder's boolean parameter for that: )->a( n = visible b = flag ). The linter rule unconverted-abap-boolean catches it.

Timestamp ​

timestamp and timestampl go on the wire as an ISO string in UTC, 2024-01-15T12:30:00Z (timestampl with its fraction), and the framework reads that shape back. For a property that wants a Date object, Formatter.DateCreateObject reads the string as it is — see the formatters abap2UI5 ships. For an editable value, two practical approaches:

Split in ABAP — break the timestamp into separate d and t fields before sending, bind each with the Date / Time formatter above, recombine after the event. Simplest when the UI shows date and time as separate fields anyway.

Send as string with a source pattern — convert to a string attribute in yyyyMMddHHmmss format on the ABAP side, then bind with sap.ui.model.type.DateTime:

abap
)->tag( `DateTimePicker`
    )->a( n = `value` v = |\{ path: '{ client->_bind_path( mv_ts_string ) }',|
                       && | type: 'sap.ui.model.type.DateTime',|
                       && | formatOptions: \{ pattern: 'yyyy-MM-dd HH:mm:ss',|
                       && | source: \{ pattern: 'yyyyMMddHHmmss' \} \} \}|

Conversion happens in ABAP (ts_string = |{ timestamp }| yields those 14 digits for a timestamp); the framework moves the string verbatim.

A custom JS formatter is the third option when neither fits.

The formatters abap2UI5 ships ​

A UI5 type covers the value property, which is a string. It does not cover a property that wants a JavaScript Date object — DatePicker.dateValue, PlanningCalendarAppointment.startDate — and JSON has no date type, so the model physically cannot carry one. For that, and for one text case, the framework ships a small curated formatter module. It is a public contract: z2ui5/model/formatter, reached through core:require, which every UI5 release abap2UI5 supports understands, 1.71 included. It is the only formatter module the frontend has; what it replaced is on Deprecations.

Load it once on the view root, then name a helper in the binding string:

abap
view->a( n = `core:require` v = `{Formatter: 'z2ui5/model/formatter'}` ).

...

)->tag( `DatePicker`
    )->a( n = `dateValue` v = |\{ path: '{ client->_bind_path( mv_date ) }',|
                           && | formatter: 'Formatter.DateCreateObject' \}|

mv_date is a d, so it arrives as 2024-01-15, which DateCreateObject reads. The DateAbapDate… helpers are for a date held as an eight-digit string instead — a c LENGTH 8 key or a legacy structure field. The JavaScript Date constructor reads a bare ISO date as midnight UTC, so west of Greenwich the picker shows the day before; where that matters, bind the value with the Date type instead.

HelperTakesReturns
DateAbapDateToDateObjectan ABAP date held as an eight-digit string (20240115) — not a d attribute, which arrives as 2024-01-15a Date at midnight local time
DateAbapDateTimeToDateObjectthe same date string and a six-digit time string (123000) as two parts (the time may be omitted → midnight)a Date with the time applied
DateCreateObjectanything the JS Date constructor parses (an ISO string: a d, timestamp or utclong attribute)a Date
expandInlineIconsa formatted-text string carrying %%icon:sap-icon://<name>%% placeholdersthe same text with the theme's icon glyphs inlined — for a MessageStrip text

An initial or empty value yields null, never an Invalid Date. That matters more than it sounds: an Invalid Date is truthy, so a control accepts it and fails much later — a sap.ui.unified calendar throws for every rendered day and takes the whole view down. null is what "no date" means to a UI5 date property, so an optional date field in a bound row stays empty instead.

The module grows through framework pull requests only; a helper of your own goes in your own module and is required the same way. See Z2UI5_CL_SMP_APP_457 (DatePicker) and Z2UI5_CL_SMP_APP_456 (PlanningCalendar) in the samples repository.

Full Worked Example ​

The class below combines the Currency and Digit Sequence patterns in one app and demonstrates every formatOptions variant listed under Currency:

abap
CLASS zcl_sample_currency DEFINITION PUBLIC.

  PUBLIC SECTION.
    INTERFACES z2ui5_if_app.
    DATA amount   TYPE p LENGTH 14 DECIMALS 3.
    DATA currency TYPE string.
    DATA numeric  TYPE n LENGTH 12.

  PROTECTED SECTION.
    DATA client TYPE REF TO z2ui5_if_client.

    METHODS view_display.

  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_sample_currency IMPLEMENTATION.

  METHOD z2ui5_if_app~main.

    me->client = client.

    CASE abap_true.
      WHEN client->check_on_init( ).
        numeric  = `000000000012`.
        amount   = `123456789.123`.
        currency = `USD`.
        view_display( ).
      WHEN client->check_on_navigated( ).
        view_display( ).
      WHEN client->check_on_event( `BUTTON` ).
        " the roundtrip is the point of this button: the edited values travel
        " to the server and come back, and every formatter above renders them
        " again from the model
        client->message_toast_display( |Amount { amount }, currency { currency }| ).
    ENDCASE.

  ENDMETHOD.

  METHOD view_display.

    DATA(view) = z2ui5_cl_ui5_view_builder=>factory(
        )->ele( n = `View` ns = `mvc`
            )->a( n = `xmlns`      v = `sap.m`
            )->a( n = `xmlns:mvc`  v = `sap.ui.core.mvc`
            )->a( n = `xmlns:form` v = `sap.ui.layout.form`

            )->ele( `Shell`
                )->ele( `Page`
                    )->a( n = `title`          v = `abap2UI5 - Currency Format`
                    )->a( n = `navButtonPress` v = client->_event_nav_app_leave( )
                    )->a( n = `showNavButton`  b = client->check_app_prev_stack( )

                    )->ele( n = `SimpleForm` ns = `form`
                        )->a( n = `title`    v = `Currency`
                        )->a( n = `editable` b = abap_true

                        )->ele( n = `content` ns = `form`
                            )->tag( `Title`
                                )->a( n = `text` v = `Input`
                            )->tag( `Label`
                                )->a( n = `text` v = `Documentation`
                            )->tag( `Link`
                                )->a( n = `text`   v = `https://sdk.openui5.org/api/sap.ui.model.type.Currency`
                                )->a( n = `href`   v = `https://sdk.openui5.org/api/sap.ui.model.type.Currency`
                                )->a( n = `target` v = `_blank`

                            )->tag( `Label`
                                )->a( n = `text` v = `One field`
                            )->tag( `Input`
                                )->a( n = `value` v = |\{ parts: [ '{ client->_bind_path( amount ) }',|
                                                   && | '{ client->_bind_path( currency ) }' ],|
                                                   && | type: 'sap.ui.model.type.Currency' \}|
                            )->tag( `Label`
                                )->a( n = `text` v = `Two fields`
                            )->tag( `Input`
                                )->a( n = `value` v = |\{ parts: [ '{ client->_bind_path( amount ) }',|
                                                   && | '{ client->_bind_path( currency ) }' ],|
                                                   && | type: 'sap.ui.model.type.Currency',|
                                                   && | formatOptions: \{ showMeasure: false \} \}|
                            )->tag( `Label`
                                )->a( n = `text` v = `Two fields`
                            )->tag( `Input`
                                )->a( n = `value` v = |\{ parts: [ '{ client->_bind_path( amount ) }',|
                                                   && | '{ client->_bind_path( currency ) }' ],|
                                                   && | type: 'sap.ui.model.type.Currency',|
                                                   && | formatOptions: \{ showNumber: false \} \}|
                            )->tag( `Label`
                                )->a( n = `text` v = `Default`
                            )->tag( `Text`
                                )->a( n = `text` v = |\{ parts: [ '{ client->_bind_path( amount ) }',|
                                                   && | '{ client->_bind_path( currency ) }' ],|
                                                   && | type: 'sap.ui.model.type.Currency' \}|
                            )->tag( `Label`
                                )->a( n = `text` v = `preserveDecimals:false`
                            )->tag( `Text`
                                )->a( n = `text` v = |\{ parts: [ '{ client->_bind_path( amount ) }',|
                                                   && | '{ client->_bind_path( currency ) }' ],|
                                                   && | type: 'sap.ui.model.type.Currency',|
                                                   && | formatOptions: \{ preserveDecimals: false \} \}|
                            )->tag( `Label`
                                )->a( n = `text` v = `currencyCode:false`
                            )->tag( `Text`
                                )->a( n = `text` v = |\{ parts: [ '{ client->_bind_path( amount ) }',|
                                                   && | '{ client->_bind_path( currency ) }' ],|
                                                   && | type: 'sap.ui.model.type.Currency',|
                                                   && | formatOptions: \{ currencyCode: false \} \}|
                            )->tag( `Label`
                                )->a( n = `text` v = `style:'short'`
                            )->tag( `Text`
                                )->a( n = `text` v = |\{ parts: [ '{ client->_bind_path( amount ) }',|
                                                   && | '{ client->_bind_path( currency ) }' ],|
                                                   && | type: 'sap.ui.model.type.Currency',|
                                                   && | formatOptions: \{ style: 'short' \} \}|
                            )->tag( `Label`
                                )->a( n = `text` v = `style:'long'`
                            )->tag( `Text`
                                )->a( n = `text` v = |\{ parts: [ '{ client->_bind_path( amount ) }',|
                                                   && | '{ client->_bind_path( currency ) }' ],|
                                                   && | type: 'sap.ui.model.type.Currency',|
                                                   && | formatOptions: \{ style: 'long' \} \}|

                            )->tag( `Label`
                                )->a( n = `text` v = `event`
                            )->tag( `Button`
                                )->a( n = `text`  v = `send`
                                )->a( n = `press` v = client->_event( `BUTTON` )

                        )->end(
                    )->end(

                    " Remove leading zeros from a numeric string with OData type formatting.
                    " isDigitSequence: true tells the formatter to treat the value as a digit
                    " sequence — resolves to: { path: "/NUMERIC",
                    " type: 'sap.ui.model.odata.type.String',
                    " constraints: { isDigitSequence: true } }
                    )->ele( n = `SimpleForm` ns = `form`
                        )->a( n = `title`    v = `No Zeros`
                        )->a( n = `editable` b = abap_true

                        )->ele( n = `content` ns = `form`
                            )->tag( `Title`
                                )->a( n = `text` v = `Input`
                            )->tag( `Label`
                                )->a( n = `text` v = `Documentation`
                            )->tag( `Link`
                                )->a( n = `text`   v = `https://sdk.openui5.org/api/sap.ui.model.odata.type.String%23methods/formatValue`
                                )->a( n = `href`   v = `https://sdk.openui5.org/api/sap.ui.model.odata.type.String%23methods/formatValue`
                                )->a( n = `target` v = `_blank`
                            )->tag( `Label`
                                )->a( n = `text` v = `Numeric`
                            )->tag( `Input`
                                )->a( n = `value` v = client->_bind( numeric )
                            )->tag( `Label`
                                )->a( n = `text` v = `Without leading Zeros`
                            )->tag( `Text`
                                )->a( n = `text` v = |\{ path: '{ client->_bind_path( numeric ) }',|
                                                  && | type: 'sap.ui.model.odata.type.String',|
                                                  && | constraints: \{ isDigitSequence: true \} \}| ).

    client->view_display( view->stringify( ) ).

  ENDMETHOD.

ENDCLASS.

The page's back button is the current idiom: navButtonPress wired to client->_event_nav_app_leave( ) leaves the app without a branch in main( ), and showNavButton bound to check_app_prev_stack( ) shows the button only when there is an app to return to. The same class is sample Z2UI5_CL_SMP_APP_067 in the samples repository.

Working Samples ​

Complete apps from the sample catalog that use what this page describes. Each is a single class in abap2UI5/samples unless its row names another of the three sample repositories — pull that repository with abapGit and start the class with ?app_start=<class>.

SampleClass
Currency Amounts (sap.ui.model.type.Currency)Z2UI5_CL_SMP_APP_067
ABAP Date and Time Strings (DATS/TIMS)Z2UI5_CL_SMP_APP_450
Date Object for the DatePickerZ2UI5_CL_SMP_APP_457
Date Objects for the PlanningCalendarZ2UI5_CL_SMP_APP_456
Inline Icons in a TextZ2UI5_CL_SMP_APP_466
When Not to Use One: Compute in ABAPZ2UI5_CL_SMP_APP_453