Feature Showcase App Guide - SAP-samples/abap-platform-fiori-feature-showcase GitHub Wiki
Tip
A newer version of the Guide is also available, separated into 6 files. Please refer to README.
Tips on how to use this Guide:
When you see a feature that you would like to implement, copy or take note of the search term (e.g., #SearchTermExample) and perform a search here. You will be presented with
- a short description of the feature,
- code snippets and where to find them in the source code,
- and in some cases, a link to the official RAP documentation for more information.
💡 Take note that the links will always lead you to the RAP documentation for the latest release! You have to take into account the version of the system you have.
Alternatively, you can search for an annotation here, get the search term, and use it to locate the UI feature in the app. If the annotation cannot be found, it could simply mean that it is not showcased in the current release.
Search term: #IANATimezone
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
With the annotation @Semantics.timeZone
you can convert a timezone to one specified according to the IANA standard. You are also able to assign this converted timezone to a timestamp (which has to be in the UTC format) so that the time will be interpreted in this timezone. The annotation to use is @Semantics.timeZoneReference
.
The conversion of the timezone is happening at the backend, while the timestamp conversion is done by the UI.
This feature is also available for use with action/function parameters.
In the following example, changing the SAPTimezone
field will also change IANATimezone
and IANATimestamp
, which are both shown in IANA standard and changing Timestamp
will change IANATimestamp
automatically. This is achieved via side effect.
Note
Source: CDS View /DMO/FSA_R_RootTP
// Search Term #IANATimezone
@Consumption.valueHelpDefinition: [{ entity: { name: 'I_TimeZone', element: 'TimeZoneID' } }]
SAPTimezone,
@Semantics.timeZone: true
SAPTimezone as IANATimezone,
Timestamp,
@Semantics.timeZoneReference: 'IANATimezone'
Timestamp as IANATimestamp,
// End Search Term #IANATimezone
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #IANATimezone
@UI.facet: [
{
parentId : 'Nested',
id : 'TimeAndDate',
label : 'Time and Date (#TimeAndDate)',
type : #COLLECTION
},
// Search Term #IANATimezone
{
parentId : 'TimeAndDate',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'TimezoneInput',
label : 'SAP Timezone'
},
{
parentId : 'TimeAndDate',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'TimezoneOutput',
label : 'IANA Timezone'
}
]
@UI.fieldGroup: [
{
qualifier: 'TimezoneInput',
position: 10,
label: 'SAP Timezone'
},
{
qualifier: 'TimezoneInput',
dataAction: 'overwriteTimezone',
type: #FOR_ACTION,
emphasized: true,
label: 'Overwrite Timezone (#IANATimezoneAParameter)'
}
]
SAPTimezone;
@UI.fieldGroup: [{
qualifier: 'TimezoneOutput',
position: 10,
label: 'IANA Timezone (#IANATimezone)'
}]
IANATimezone;
@UI.fieldGroup: [{
qualifier: 'TimezoneInput',
position: 20
}]
Timestamp;
@UI.fieldGroup: [{
qualifier: 'TimezoneOutput',
position: 20,
label: 'IANA Timestamp (#IANATimezone)'
}]
IANATimestamp;
// End Search Term #IANATimezone
Side effects for timezone
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
side effects {
field SAPTimezone affects field IANATimestamp, field IANATimezone;
field Timestamp affects field IANATimestamp;
}
}
Search term: #ValueHelps, #DependentFilter
The implementation of a value help in CDS enables the end user to choose values from a predefined list for input fields on a user interface.
The additional binding defines a second condition for the value help on the same target value help provider entity for filtering the value help result list and/or returning values from the selected value help record. The additional binding can be defined for an additional element or parameter. Depending on the value provided in usage, the additional binding works as a filter, result or filter and result condition
Usage: #Result: The referenced element or parameter in localElement
or localParameter
is filled with the value provided by the value help. When creating an instance, you can fill various fields with this option.
Note
Source: CDS View /DMO/FSA_R_RootTP
// Search Term #ValueHelps
@Consumption.valueHelpDefinition: [
{
entity: { name: '/DMO/FSA_I_Criticality', element: 'Code' },
additionalBinding: [{ element: 'Name',
localElement: 'FieldWithCriticality',
usage: #RESULT }]
}
]
CriticalityCode,
Usage: #Filter : The value of the referenced element or parameter in localElement
or localParameter
is used as a filter for the value help. The value help only displays filtered results.
// Search Term #DependentFilter
@Consumption.valueHelpDefinition: [
{
entity: { name: '/DMO/FSA_I_Contact', element: 'ID' },
label: 'Contacts',
additionalBinding: [{ element: 'Country',
localElement: 'Country',
usage: #FILTER }]
}
]
ContactID,
You can influence what is shown in the value help using @Consumption.valueHelpDefault.display
. In the example below, everything except for ID (Name), phone, country, street, city and postcode would be hidden in the value help.
Note
Source: Source: CDS View /DMO/FSA_I_Contact
define view entity /DMO/FSA_I_Contact
...
{
@ObjectModel.text.element: ['Name'] // Search Term #DisplayTextAndID
@UI.textArrangement: #TEXT_ONLY
@EndUserText.label: 'Contact'
key id as ID,
@Consumption.valueHelpDefault.display:false
name as Name,
@Consumption.valueHelpDefault.display:true
phone as Phone,
@Consumption.valueHelpDefault.display:false
building as Building,
@Consumption.valueHelpDefault.display:true
country as Country,
@Consumption.valueHelpDefault.display:true
street as Street,
@Consumption.valueHelpDefault.display:true
city as City,
@Consumption.valueHelpDefault.display:true
postcode as Postcode,
@Consumption.valueHelpDefault.display:false
address_label as AddressLabel,
@Consumption.valueHelpDefault.display:false
photo_url as PhotoUrl,
...
}
For smaller collections of possible values in the value help, it might be a good idea to have a dropdown instead of a dialog to choose the value. This can be achieved with the @ObjectModel : { resultSet.sizeCategory: #XS }
Note
Source: CDS View /DMO/FSA_I_Criticality
@ObjectModel : { resultSet.sizeCategory: #XS }
define view entity /DMO/FSA_I_Criticality
...
More Information: ABAP RESTful Application Programming Model - Providing Value Help
Search term: #useForValidationVH
Warning
Only shown in the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
To mark a value help as an input validator, one can use the keyword useForValidation: true
in the annotation @Consumption.valueHelpDefinition
. It can be annotated at a field, a CDS parameter or an action parameter.
It is good practice to use the keyword qualifier
for every value help, even if the field only has one. If you have defined more than one value help at a field, useForValidation
might not work correctly if you have forgotten to use qualifiers, as UI would not be able to determine which value help is to be used for validation.
This keyword does not work for collective value helps.
💡 If you have a draft-enabled app, using this annotation prevents an invalid value from being saved to draft. A refresh of the page will clear the user input.
💡 Another alternative to this annotation would be to use a drop down list with @ObjectModel : { resultSet.sizeCategory: #XS }
, if there are not too many available choices.
Note
Source: CDS View /DMO/FSA_R_RootTP
// Search Term #useForValidationVH
@Consumption.valueHelpDefinition: [{ entity: { name: 'I_RegionVH', element: 'Region' },
qualifier: 'RegionValueHelp',
useForValidation: true,
additionalBinding: [{ element: 'Country',
localElement: 'Country' }] }]
Region,
Search term: #StaticFeatureCtrl
Each field can have specific access restrictions, defined in the behaviour definition. If the access restriction is always the same for each instance, you can use static feature control. Some examples/possible combinations are described here:
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
field ( readonly, numbering : managed ) ID;
field ( mandatory ) Email;
field ( mandatory : create, readonly : update ) StringProperty;
}
There are 2 different types of readonly:
field ( readonly, numbering : managed ) ID;
means that the field ID
is a key that will be assigned a value by the framework (numering:managed) and must not be created or updated by the user at all (readonly). The annotation in $metadata is <Annotation Term="SAP__core.Computed"/>
.
field ( mandatory : create, readonly : update ) StringProperty;
means that the field StringProperty
is only mandatory during create, but after that it will be read only. The annotation for the readonly in $metadata is <Annotation Term="SAP__core.Immutable"/>
.
field ( mandatory ) Email;
means that the user must provide a value for the field Email
. The annotation in $metadata is <Annotation Term="SAP__common.FieldControl" EnumMember="SAP__common.FieldControlType/Mandatory"/>
.
More Information: ABAP RESTful Application Programming Model - Static Feature Control
Each field can have specific access restrictions, defined in the behaviour definition and behaviour implementation. If the access restriction depends on a certain condition, you can implement the feature control dynamically.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
field ( features : instance ) TimesChildCreated;
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_ROOTTP
METHOD get_instance_features.
result = VALUE #( FOR root IN roots
( %tky = root-%tky
%field-TimesChildCreated = if_abap_behv=>fc-f-read_only
) ).
ENDMETHOD.
In this simple example, the field TimesChildCreated
is dynamically assigned the restriction read-only.
The annotation in $metadata is <Annotation Term="SAP__common.FieldControl" Path="__FieldControl/TimesChildCreated"/>
.
For dynamic control of operations and actions, the option (features: instance) must be added to the operation or action.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
delete (features : instance);
action ( features : instance ) changeProgress parameter /DMO/FSA_D_ChangeProgressP result [1] $self;
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_ROOTTP
METHOD get_instance_features.
READ ENTITIES OF /DMO/FSA_R_RootTP IN LOCAL MODE
ENTITY Root
FIELDS ( UpdateHidden DeleteHidden ) WITH CORRESPONDING #( keys )
RESULT DATA(roots)
FAILED failed.
result = VALUE #( FOR root IN roots
( %tky = root-%tky
%delete = COND #( WHEN root-DeleteHidden = abap_true
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
%action-changeProgress = COND #( WHEN root-UpdateHidden = abap_true
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
) ).
ENDMETHOD.
The delete operation and action ChangeProgress
will be disabled if the fields DeleteHidden
or UpdateHidden
has boolean value abap_true, and vice-versa.
More Information: ABAP RESTful Application Programming Model - Dynamic Feature Control
An action that is defined via Datafield ForAction is not tied to a specific data value. Therefore it is possible to assign the annotation to any arbitary element. Whether the action button is to be in the list report or object page, line item or section, this largely depends on the respective UI annotation you use. More examples are listed below in this guide, if you search for action
.
The keyword to use for this is type: #FOR_ACTION
in @UI.lineItem
, @UI.fieldGroup
, etc.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search Term #OPForm
{
purpose : #HEADER, // or #STANDARD,
label : 'FieldGroup (#OPForm)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'OPForm',
id: 'SubSectionID'
}
]
@UI: {
lineItem: [
// Search Term #ActionInLineItem
{
type:#FOR_ACTION,
label: 'Change Criticality (#ActionInLineItem)',
dataAction: 'changeCriticality',
position: 10
}
],
fieldGroup: [
// Search Term #ActionInSection
{
qualifier: 'OPForm',
dataAction: 'changeProgress',
type: #FOR_ACTION,
emphasized: true,
label: 'Change Progress (#ActionInSection)'
}
]
}
LastChangedAt;
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
action changeCriticality parameter /DMO/FSA_D_ChangeCriticalityP result [1] $self;
action changeProgress parameter /DMO/FSA_D_ChangeProgressP result [1] $self;
More Information: ABAP RESTful Application Programming Model - Actions
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
An action that is tied to a data value, which would be rendered as a hyperlink. Therefore it is crucial to specify the annotation at the desired element which has the data value. Whether the action button is to be in the list report or object page, line item or section, this largely depends on the respective UI annotation you use.
The keyword to use for this is type: #WITH_ACTION
in @UI.lineItem
, @UI.fieldGroup
, @UI.identification
.
More Information:
- List Report - Content Area - Datafield WithAction in Line Item
- Object Page - Header Area - Datafield WithAction in Object Page
Search term: #ValueHelpParameter
Often properties of an entity have value helps, so that creating a new entity is easier and wrong inputs are reduced. Value helps for action parameters are also possible.
Note
Source: CDS Abstract Entity /DMO/FSA_D_ChangeCriticalityP
// Search Term #ValueHelpParameter
@Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/FSA_I_Criticality', element: 'Code' }}]
criticality_code : abap.int4;
This can be achieved, by just annotating the parameter with @Consumption.valueHelpDefinition
.
Search term: #ParameterDefaultValue
With the annotation @UI.defaultValue
a default value for the parameter is set. A fixed string value can be given or a property from the entity can be reference using syntax #( 'ELEMENT_OF_REFERENCED_ENTITY: <field_name>' )
.
Note
Source: CDS Abstract Entity /DMO/FSA_D_ChangeCriticalityP
// Search Term #ParameterDefaultValue
@UI.defaultValue : #( 'ELEMENT_OF_REFERENCED_ENTITY: CriticalityCode')
criticality_code : abap.int4;
Warning
Only shown in the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
An action parameter now inherits the text label from the underlying data element. No additional effort is required other than maintaining the label (and localized text label) at the data element itself. For comparison, see the examples below.
Label from data element:
Note
Source: Abstract Entity /DMO/FSA_D_ChangeCriticalityP
criticality_code : /dmo/fsa_criticality;
Label from annotation:
Note
Source: Abstract Entity /DMO/FSA_D_ChangeProgressP
@EndUserText.label: 'Change Progress'
progress : abap.int4;
Search term: #IANATimezoneAParameter
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
With the annotation @Semantics.timeZone
you can convert a timezone to one specified according to the IANA standard. You are also able to assign this converted timezone to a timestamp (which has to be in the UTC format) so that the time will be interpreted in this timezone. The annotation to use is @Semantics.timeZoneReference
.
The conversion of the timezone is happening at the backend, while the timestamp conversion is done by the UI.
This feature is also available for general use.
In the following example, the action overwriteTimezone
expects a timezone input. Choosing a value using the value help will fill in the IANA Timezone
as well.
Note
Source: Abstract Entity /DMO/FSA_D_OverwriteTimezoneP
@EndUserText.label: 'Oerwrite Timezone parameter'
define root abstract entity /DMO/FSA_D_OverwriteTimezoneP
{
// Search Term #MandatoryParameter
@EndUserText.label: 'Timezone (#MandatoryParameter)'
@Consumption.valueHelpDefinition: [{ entity: { name: 'I_TimeZoneIANACodeMap', element: 'TimeZoneID' },
additionalBinding: [{ usage: #RESULT, localElement: 'iana_timezone', element: 'TimeZoneIANACode' }] }]
sap_timezone : tznzone;
// Search Term #IANATimezoneAParameter
@Semantics.timeZone: true
@EndUserText.label: 'IANA timezone (#IANATimezoneAParameter)'
iana_timezone : tznzone;
}
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
...
action ( features : instance ) overwriteTimezone deep parameter /DMO/FSA_D_OverwriteTimezoneP;
...
}
Note
Source: CDS View /DMO/FSA_R_RootTP
// Search Term #IANATimezone
@Consumption.valueHelpDefinition: [{ entity: { name: 'I_TimeZone', element: 'TimeZoneID' } }]
SAPTimezone,
Note
Source: Metadata Extention /DMO/FSA_C_RootTP
// Search Term #IANATimezone
@UI.facet: [
{
parentId : 'Nested',
id : 'TimeAndDate',
label : 'Time and Date (#TimeAndDate)',
type : #COLLECTION
},
// Search Term #IANATimezone
{
parentId : 'TimeAndDate',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'TimezoneInput',
label : 'SAP Timezone'
}
]
@UI.fieldGroup: [
{
qualifier: 'TimezoneInput',
dataAction: 'overwriteTimezone',
type: #FOR_ACTION,
emphasized: true,
label: 'Overwrite Timezone (#IANATimezoneAParameter)'
}
]
SAPTimezone;
Search term: #MandatoryParameter
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
It is possible to define mandatory parameters for action/functions but to do this, you would need a behaviour definition for the abstract entity. This is typically a deep parameter with a hierarchy structure but instead of a true hierarchy with associations, we define the abstract entity as a flat structure.
In this example, the field sap_timezone
should be a mandatory parameter and will be marked with a red asterisk (*) . The keyword to use is mandatory:execute
, to be marked at the field in the behaviour definition.
Note
Source: Abstract Entity /DMO/FSA_D_OverwriteTimezoneP
@EndUserText.label: 'Oerwrite Timezone parameter'
define root abstract entity /DMO/FSA_D_OverwriteTimezoneP
{
// Search Term #MandatoryParameter
@EndUserText.label: 'Timezone (#MandatoryParameter)'
@Consumption.valueHelpDefinition: [{ entity: { name: 'I_TimeZoneIANACodeMap', element: 'TimeZoneID' },
additionalBinding: [{ usage: #RESULT, localElement: 'iana_timezone', element: 'TimeZoneIANACode' }] }]
sap_timezone : tznzone;
// Search Term #IANATimezoneAParameter
@Semantics.timeZone: true
@EndUserText.label: 'IANA timezone (#IANATimezoneAParameter)'
iana_timezone : tznzone;
}
Important keywords for the behaviour definition are abstract
, with hierarchy;
and with control
.
Note
Source: Behaviour Definition /DMO/FSA_D_OverwriteTimezoneP
abstract;
strict ( 2 );
with hierarchy;
define behavior for /DMO/FSA_D_OverwriteTimezoneP with control
{
field (mandatory:execute) sap_timezone;
}
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
...
action ( features : instance ) overwriteTimezone deep parameter /DMO/FSA_D_OverwriteTimezoneP;
...
}
More information: ABAP RESTful Application Programming Model - Modeling Parameters for Non-Standard Operations
Search term: #DefaultFunctionForCreate, #DefaultFunctionForAction, #DefaultFunctionForCBA
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
With a default values function you can default the input parameters for actions, functions, as well as create and create-by-association operations, similar to the annotation @UI.defaultValue
(see Default Value for action parameter). The difference here is, with default values function you can specify the values using more complicated coding.
The general rules are:
- Function name must begin with
GetDefaultsFor
- Function name must be unique within the current BDEF
- In certain cases, external names can be given
- Key word is
{default function GetDefaultsForxxx;}
behind the respective operation
The importing parameter and the return type of the function need not be specified, as they will be derived by the framework from the respective actions/operations. If you have a projection layer, it is necessary to expose the default values function too in the projection BDEF.
In this example, the property StringProperty
, which is a mandatory input for create, will be prefilled with the value Default Value for Root Create
.
Further rules:
- Function name after the keyword
default function
is optional. When specified it must beGetDefaultsForCreate
- External name is not possible
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
// Search Term #DefaultFunctionForCreate
create { default function GetDefaultsForCreate; }
}
Note
Source: Behaviour Definition /DMO/FSA_C_RootTP
define behavior for /DMO/FSA_C_RootTP alias Root
...
{
use create;
use function GetDefaultsForCreate;
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_RootTP
METHODS GetDefaultsForCreate FOR READ
IMPORTING keys FOR FUNCTION Root~GetDefaultsForCreate RESULT result.
METHOD GetDefaultsForCreate.
result = VALUE #( FOR key IN keys
( %cid = key-%cid
%param = VALUE #( StringProperty = 'Default Value for Root Create' ) ) ).
ENDMETHOD.
In this example, the property StringProperty
, which is a mandatory input for Child create, will be prefilled with the value Default Value for Child Create
. Property FieldWithPercent
will also be prefilled to avoid triggering a validation error when saving (this is not shown in the pop up during create, but the code can be found in the behaviour implementation).
Further rules:
-
default function
must be specified in combination with create within curly brackets for an association. - External name is possible
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
// Search Term #DefaultFunctionForCBA
association _Child { create { default function GetDefaultsForChild external 'GetDefaultsForCreateByAssociation'; } with draft; }
}
Note
Source: Behaviour Definition /DMO/FSA_C_RootTP
define behavior for /DMO/FSA_C_RootTP alias Root
...
{
use association _Child { create; with draft; }
use function GetDefaultsForChild;
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_RootTP
METHODS GetDefaultsForChild FOR READ
IMPORTING keys FOR FUNCTION Root~GetDefaultsForChild RESULT result.
METHOD GetDefaultsForCreate.
result = VALUE #( FOR key IN keys
( %tky = key-%tky
%param = VALUE #( StringProperty = 'Default Value for Child Create'
FieldWithPercent = '1.0' ) ) ).
ENDMETHOD.
In this example, the property valid_to
in input parameter /DMO/FSA_D_SelectInstanceP
will be prefilled with a date. This date will in turn be used as a filter for the value help of Semantic Key
.
Further rules:
- The action/function must specify an input parameter. Flat, deep, and deep table parameters are supported.
- External name is possible
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
// Search Term #DefaultFunctionForAction
action ( features : instance ) selectInstance parameter /DMO/FSA_D_SelectInstanceP { default function GetDefaultsForSelectInstance; }
}
Note
Source: Behaviour Definition /DMO/FSA_C_RootTP
define behavior for /DMO/FSA_C_RootTP alias Root
...
{
use action selectInstance;
use function GetDefaultsForSelectInstance;
}
Note
Source: Abstract Entity /DMO/FSA_D_SelectInstanceP
// Search Term #DefaultFunctionForAction
define abstract entity /DMO/FSA_D_SelectInstanceP
{
@Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/FSA_RootVH' , element: 'StringProperty' },
additionalBinding: [{ element: 'ValidTo',
localElement: 'valid_to',
usage: #FILTER }] }]
@EndUserText.label: 'Semantic Key'
string_property : abap.char(256) ;
@EndUserText.label: 'Valid To'
valid_to: abap.dats;
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_RootTP
METHODS GetDefaultsForSelectInstance FOR READ
IMPORTING keys FOR FUNCTION Root~GetDefaultsForSelectInstance RESULT result.
METHOD GetDefaultsForSelectInstance.
DATA: lv_validto TYPE d.
SELECT SINGLE validto
FROM /DMO/FSA_RootVH
WHERE validto IS NOT INITIAL
INTO @DATA(lv_validto).
result = VALUE #( FOR key IN keys
( %tky = key-%tky
%param = VALUE #( valid_to = lv_validto ) ) ).
ENDMETHOD.
More information: ABAP RESTful Application Programming Model - Operation Defaulting
Search term: #RecommendedDataTypesSection
To define the data model of our business object, we have to create tables to store the data that the CDS view is built upon. For the backend to derive the correct data types for oData, there is a list of recommended, released built in ABAP types and data elements that you can use. There are used in the app and can be seen in the Object Page under Data Types(#RecommendedDataTypesSection)
.
Note
Source: Database Table /DMO/FSA_Root_A
define table /dmo/fsa_root_a {
key client : abap.clnt not null;
...
type_accp : abap.accp;
type_bool : abap_boolean;
type_char : abap.char(256);
type_clnt : abap.clnt;
type_cuky : abap.cuky;
@Semantics.amount.currencyCode : '/dmo/fsa_root_a.type_cuky'
type_curr : abap.curr(10,2);
type_dec_amount : abap.dec(10,2);
type_datn : abap.datn;
type_dats : abap.dats;
type_dec : abap.dec(12,4);
@AbapCatalog.decfloat.outputStyle : #NORMAL
type_df16_dec : abap.df16_dec(10,4);
type_fltp : abap.fltp;
type_int1 : abap.int1;
type_int2 : abap.int2;
type_int4 : abap.int4;
type_int8 : abap.int8;
type_lang : abap.lang;
type_numc : abap.numc(128);
@Semantics.quantity.unitOfMeasure : '/dmo/fsa_root_a.type_unit'
type_quan : abap.quan(20,4);
type_fltp_quan : abap.fltp;
type_rawstring : abap.rawstring(0);
type_sstring : abap.sstring(256);
type_string : abap.string(0);
type_timn : abap.timn;
type_tims : abap.tims;
type_unit : abap.unit(3);
type_tzntstmps : tzntstmps;
type_tzntstmpl : tzntstmpl;
type_dec_time : abap.dec(21,7);
type_utclong : abap.utclong;
stream_mimetype : abap.char(128);
@AbapCatalog.decfloat.outputStyle : #NORMAL
type_df34_dec : abap.df34_dec(31,10);
}
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
annotate entity /DMO/FSA_C_RootTP with
{
@UI.facet: [
// Search Term #RecommendedDataTypesSection
{
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'DataTypes',
label: 'Data Types(#RecommendedDataTypesSection)'
}
]
@UI.fieldGroup: [{ position: 10, qualifier: 'DataTypes' }]
TypeAccp;
@UI.fieldGroup: [{ position: 20, qualifier: 'DataTypes' }]
TypeBool;
@UI.fieldGroup: [{ position: 30, qualifier: 'DataTypes' }]
TypeChar;
@UI.fieldGroup: [{ position: 40, qualifier: 'DataTypes' }]
TypeClnt;
@UI.fieldGroup: [{ position: 50, qualifier: 'DataTypes' }]
TypeCurr;
@UI.fieldGroup: [{ position: 60, qualifier: 'DataTypes' }]
TypeDecAmount;
@UI.fieldGroup: [{ position: 70, qualifier: 'DataTypes' }]
TypeDatn;
@UI.fieldGroup: [{ position: 80, qualifier: 'DataTypes' }]
TypeDats;
@UI.fieldGroup: [{ position: 90, qualifier: 'DataTypes' }]
TypeDec;
@UI.fieldGroup: [{ position: 100, qualifier: 'DataTypes' }]
TypeDf16Dec;
@UI.fieldGroup: [{ position: 110, qualifier: 'DataTypes' }]
TypeDf34Dec;
@UI.fieldGroup: [{ position: 120, qualifier: 'DataTypes' }]
TypeFltp;
@UI.fieldGroup: [{ position: 130, qualifier: 'DataTypes' }]
TypeInt1;
@UI.fieldGroup: [{ position: 140, qualifier: 'DataTypes' }]
TypeInt2;
@UI.fieldGroup: [{ position: 150, qualifier: 'DataTypes' }]
TypeInt4;
@UI.fieldGroup: [{ position: 160, qualifier: 'DataTypes' }]
TypeInt8;
@UI.fieldGroup: [{ position: 170, qualifier: 'DataTypes' }]
TypeNumc;
@UI.fieldGroup: [{ position: 180, qualifier: 'DataTypes' }]
TypeQuan;
@UI.fieldGroup: [{ position: 190, qualifier: 'DataTypes' }]
TypeFltpQuan;
@UI.fieldGroup: [{ position: 200, qualifier: 'DataTypes' }]
TypeRawstring;
@UI.fieldGroup: [{ position: 210, qualifier: 'DataTypes' }]
TypeSstring;
@UI.fieldGroup: [{ position: 220, qualifier: 'DataTypes' }]
TypeString;
@UI.fieldGroup: [{ position: 230, qualifier: 'DataTypes' }]
TypeTimn;
@UI.fieldGroup: [{ position: 240, qualifier: 'DataTypes' }]
TypeTims;
@UI.fieldGroup: [{ position: 250, qualifier: 'DataTypes' }]
TypeUtclong;
@UI.fieldGroup: [{ position: 260, qualifier: 'DataTypes' }]
TypeTzntstmps;
@UI.fieldGroup: [{ position: 270, qualifier: 'DataTypes' }]
TypeTzntstmpl;
@UI.fieldGroup: [{ position: 280, qualifier: 'DataTypes' }]
TypeDecTime;
@UI.fieldGroup: [{ position: 290, qualifier: 'DataTypes' }]
TypeLang;
}
Search term: #QuickView
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
A quick view is a pop up that shows more information, when you click on an entry in a column or an object page. Typically, it is used in combination with one-to-one or zero-to-one associations. By clicking on the link, more information about the associated entity can be displayed.
To enable a quick view facet, the association entity needs to be annotated with @UI.facet
with type: #QUICK_VIEW
. For a better looking header of the quick view, the association entity gets typically annotated with @UI.headerInfo
. Additionally, the key value can be replaced with another text property using @ObjectModel.text.element
, so that the column is readable.
Note
Source: CDS View /DMO/FSA_I_Navigation
@UI.headerInfo: {
typeName: 'Navigation',
typeNamePlural: 'Navigations',
title.value: 'StringProperty',
description.value: 'StringProperty',
typeImageUrl: 'sap-icon://blank-tag'
}
// Search Term #QuickView
define view entity /DMO/FSA_I_Navigation
...
{
@UI.facet: [
{
type: #FIELDGROUP_REFERENCE,
label: 'Navigation',
targetQualifier: 'data',
purpose: #QUICK_VIEW
}
]
@ObjectModel.text.element: ['StringProperty'] // Search Term #DisplayTextAndID
key id as ID,
@UI.fieldGroup: [{ qualifier: 'data', position: 10 }]
string_property as StringProperty,
@UI.fieldGroup: [{ qualifier: 'data', position: 20 }]
integer_property as IntegerProperty,
@UI.fieldGroup: [{ qualifier: 'data', position: 30 }]
decimal_property as DecimalProperty,
...
}
Search term: #QuickViewNullValueIndicator
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
When your associated entity (QuickView entity) has a key that is non-UUID, a referential constraint for the association does not get generated automatically. To do so, a property needs to act as a null value indicator for the QuickView property, similar to a value control property, using the annotation @Semantics.nullValueIndicatorFor
.
Note
Source: CDS View /DMO/FSA_I_Root
define view entity /DMO/FSA_I_Root
...
association [0..1] to /DMO/FSA_I_Criticality as _Criticality on $projection.CriticalityCode = _Criticality.Code
{
@ObjectModel.foreignKey.association: '_Criticality'
criticality_code as CriticalityCode, // Property for QuickView link
// Search Term #QuickViewNullValueIndicator
@Semantics.nullValueIndicatorFor: 'CriticalityCode'
cast(' ' as abap_boolean preserving type ) as CriticalityNullValInd, // Null value indicator
...
}
Then setup your QuickView entity as usual.
Note
Source: CDS View /DMO/FSA_I_Criticality
define view entity /DMO/FSA_I_Criticality
...
{
// Search Term #QuickViewNullValueIndicator
@UI.facet: [
{
type: #FIELDGROUP_REFERENCE,
label: 'Criticality QuickView(#QuickViewNullValueIndicator)',
targetQualifier: 'QuickView',
purpose: #QUICK_VIEW
}
]
@UI: {
fieldGroup: [
{
qualifier: 'QuickView',
position: 10
}
]
}
key code as Code,
// Search Term #QuickViewNullValueIndicator
@UI.fieldGroup: [
{
qualifier: 'QuickView',
position: 20
}
]
descr as Description
}
And finally add your QuickView property to your app, in this example, using fieldgroup.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search Term #HeaderCollectionFacet
{
purpose: #HEADER,
id: 'FacetCollection',
type: #COLLECTION
},
// Search Term #HeaderFieldGroup
{
parentId : 'FacetCollection',
label : 'General Data (#HeaderFieldGroup)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'HeaderData'
}
]
@UI: {
fieldGroup: [
// Search Term #QuickViewNullValueIndicator
{
qualifier: 'HeaderData',
criticality: 'CriticalityCode',
position: 50,
label: 'Criticality QuickView(#QuickViewNullValueIndicator)'
}
]
}
CriticalityCode; // Property for QuickView link
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2022 onwards.
It is possible to download a copy of the records in List Report in the format PDF/A without any additional configuration. Take note that not all data types are supported, i.e. Stream properties are ignored.
To control which columns are to be exported, first adjust your List Report View Settings and select the columns to be shown. Then click the Dropdown button, which is next to the Export File button and choose Export As...
, or use the shortcut key Ctrl+Shift+E. Select the format Portable Document Format (*.pdf)
in the popup box and additional settings will appear. Click the Export
button to start your download.
The file will be exported to your Downloads folder for both Windows and MacOS.
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
It is possible to download a treeview in the format PDF/A without any additional configuration. Take note that not all data types are supported, i.e. Stream properties are ignored.
To control which columns are to be exported, first adjust your treeview settings and select the columns to be shown. Then click the Dropdown button, which is next to the Export File button and choose Export As...
, or use the shortcut key Ctrl+Shift+E. Select the format Portable Document Format (*.pdf)
in the popup box and additional settings will appear. Click the Export
button to start your download.
The file will be exported to your Downloads folder for both Windows and MacOS.
Search term: #LeadingEntity
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
In a service definition, it is possible to annotate the leading entity of a service binding using annotation @ObjectModel.leadingEntity.name
. This will make it easier for a user to find the starting node to start the app preview in a service binding. The leading node will have a tiny 'L' at the entity.
Note
Source: Service Definition /DMO/UI_FeatureShowcaseApp
@ObjectModel.leadingEntity.name: '/DMO/FSA_C_RootTP'
define service /DMO/UI_FeatureShowcaseApp {
...
AdaptationHidden
Search term: UI.adaptationHidden
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
Important
UI Adaptation is only possible with deployed apps. Therefore some features of this annotation cannot be showcased in the Feature Showcase App app preview, unless stated otherwise.
UI adaptation is a feature of SAPUI5 flexibility that allows key users without technical knowledge to easily make UI changes for all users of an app, end users to personalize controls, and developers to extend the UIs of SAPUI5 applications. For more information, see SAPUI5 Flexibility: Adapting UIs Made Easy.
But there are some scenarios where you do not want to allow this, that a specific property or entity should only adher to the metadata or annotations. It is possible to do this, by using the annotation @UI.adaptationHidden: true
.
As a result, the property Description
cannot
- be removed or added in, in the object page
- have its label/description be edited
- have its position on the object page be changed via drag-and-drop
In addition to the above, the property Description
cannot
- be added in as a list report filter
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
annotate entity /DMO/FSA_C_RootTP with
{
@UI.adaptationHidden: true
Description;
}
More Information: SAP Fiori Launchpad - Making UI Adaptations
Search term: #SimpleType
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
Simple types allow the definition of user-defined scalar types together with (arbitrary) domain-specific metadata via CDS annotations.
Simpler put, you can create user-defined data types in ABAP CDS, which work similarly to Data Elements in DDIC. The advantages of CDS simple types are:
- you can type them to build-in data types like
abap.int4
, DDIC data elements, or even other CDS simple types - you can use a fixed list of CDS annotations to enrich the metadata of these data types, including but not limited to:
EndUserText
,Semantics
, and others
Tip
To get the full list of allowed annotations in simple type, simply use Code Completion in ADT with Ctrl + Space after typing @
These data types can be used in CDS views by view parameters directly, or by properties via casting, and also directly by parameters in abstract entities. You can also use them in your ABAP code, especially when you are developing the behaviour implementation of RAP business objects.
Warning
Do not use CDS Simple Type with enumeration as it is not supported in RAP. CDS Simple Type is not supported in classic DDIC like tables and structures
Note
Source: Type /DMO/FSA_BT_Integer
@EndUserText.label: 'Integer Value(from Simple Type)'
@EndUserText.quickinfo: 'Integer Value'
@EndUserText.heading: 'Integer'
// Search Term #SimpleType
define type /DMO/FSA_BT_Integer: abap.int4
The simple type /DMO/FSA_BT_Integer
is typed to a build-in data type and enriched with @EndUserText
annotations.
Note
Source: Type /DMO/FSA_BT_ProgressInteger
@EndUserText.label: 'Progress Integer Value(from Simple Type)'
@EndUserText.quickinfo: 'Progress Integer Value'
@EndUserText.heading: 'Progress Integer'
// Search Term #SimpleType
define type /DMO/FSA_BT_ProgressInteger: /DMO/FSA_BT_Integer
Note
Source: Type /DMO/FSA_BT_RadialInteger
@EndUserText.label: 'Radial Integer Value(from Simple Type)'
@EndUserText.quickinfo: 'Radial Integer Value'
@EndUserText.heading: 'Radial Integer'
// Search Term #SimpleType
define type /DMO/FSA_BT_RadialInteger: /DMO/FSA_BT_Integer
The simple types /DMO/FSA_BT_ProgressInteger
and /DMO/FSA_BT_RadialInteger
are typed to another simple type, otherwise known as stacking. The types will also inherit the annotations of the base type, or they can be overwritten, as is the case here.
Note
Source: CDS View /DMO/FSA_I_Root
define view entity /DMO/FSA_I_Root...
{
...
cast ( integer_value as /DMO/FSA_BT_Integer preserving type ) as IntegerValue, // Search Term #SimpleType
}
Note
Source: CDS View /DMO/FSA_R_RootTP
define root view entity /DMO/FSA_R_RootTP...
{
...
cast ( IntegerValue as /DMO/FSA_BT_RadialInteger preserving type ) as RadialIntegerValue, // Search Term #SimpleType
cast ( IntegerValue as /DMO/FSA_BT_ProgressInteger preserving type ) as ProgressIntegerValue, // Search Term #SimpleType
}
Note
Source: Abstract Entity /DMO/FSA_D_ChangeProgressP
define abstract entity /DMO/FSA_D_ChangeProgressP
{
progress : /DMO/FSA_BT_ProgressInteger; // Search Term #SimpleType
}
All types are now used in CDS views and abstract entity and will inherit the text annotations from the simple type definition, which will be shown in UI.
More Information:
- ABAP Data Models - Simple Types
- ABAP CDS Releases CDS-Native Data Types: CDS Simple Types
- ABAP Cloud: CDS Simple Types
Search term: #FilterDefault
With the annotation @Consumption.filter.defaultValue
default values can be defined. This Annotation does not allow complex values and when switching variants, the annotation is no longer considered. For complex values the @UI.selectionVariant
annotation is a better solution.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@Consumption.filter.defaultValue: '3' // Search term #FilterDefault
CriticalityCode;
More information: ABAP RESTful Application Programming Model - Consumption Annotations
Search term: #HideFilter
To reduce the amount of available filters in a List Report, properties can be annotated with @Consumption.filter.hidden: true
to hide them.
Note
Source: Metadata Extension /DMO/FSA_C_ChartTP
//Search Term: #HideFilter
@Consumption.filter.hidden: true
AreachartTolUpperboundValue;
@Consumption.filter.hidden: true
AreachartTolLowerboundValue;
@Consumption.filter.hidden: true
AreachartDevUpperboundValue;
@Consumption.filter.hidden: true
AreachartDevLowerboundValue;
Search term: #FilterGrouping
Another nice feature is filter facet, which allows one to structure the available properties of the entity into groups, so that filter adaptation is easier.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search term #FilterGrouping
{
purpose: #FILTER,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'chartData',
label: 'Chart Data (#FilterGrouping)'
},
// Search term #FilterGrouping, #Location
{
purpose: #FILTER,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'location',
label: 'Location (#FilterGrouping)'
}
]
@UI.fieldGroup: [{ qualifier: 'chartData' }] // Search term #FilterGrouping
IntegerValue;
@UI.fieldGroup: [{ qualifier: 'chartData' }] // Search term #FilterGrouping
ForecastValue;
@UI.fieldGroup: [{ qualifier: 'chartData' }] // Search term #FilterGrouping
TargetValue;
@UI.fieldGroup: [{ qualifier: 'chartData' }] // Search term #FilterGrouping
Dimensions;
Search term: #VisibleFilters
@UI.selectionField
is the annotation which allows one to specify an array of fields, which should by default be shown in the List Report filter bar as a filter, so that the user does not need to adapt the filters.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.selectionField: [{ position: 10 }] // Search term #VisibleFilters
StringProperty;
@UI.selectionField: [{ position: 20 }] // Search term #VisibleFilters
FieldWithPrice;
@UI.selectionField: [{ position: 30 }] // Search term #VisibleFilters
IsoCurrency;
@UI.selectionField: [{ position: 40 }] // Search term #VisibleFilters
CriticalityCode;
More information: ABAP RESTful Application Programming Model - Adding Selection Fields
To see columns in your table, you would first have to define them with the annotation @UI.lineItem
at the property, either in the CDS view or in a metadata extension. The most basic setting you can use would be:
- the order of the column in the table and
- changing the column label, if you do not want to use the label from underlying views.
In the example below, StringProperty
would be the second column in the table (the numbering used here is 10, 20, etc. You could also start with 1, 2, etc. ), defined using position
. label
would be the column label/heading.
importance
denotes the importance of the property. With #HIGH
, this means that the property will always be shown even if the table is rendered on a small display.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.lineItem: [
{
position: 20,
importance: #HIGH,
label: 'Field with Sem. Key(#SemanticKey)'
}
]
StringProperty;
More information: ABAP RESTful Application Programming Model - Tables
Search term: #ActionInLineItem
With this @UI.lineItem
annotation, the action is displayed above the table on the right, with other possible actions.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #ActionInLineItem
@UI.lineItem: [
{
type:#FOR_ACTION,
label: 'Change Criticality (#ActionInLineItem)',
dataAction: 'changeCriticality',
position: 10
}
]
LastChangedAt;
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
action changeCriticality parameter /DMO/FSA_D_ChangeCriticalityP result [1] $self;
A regular action requires a line item to be selected before the button is activated but a static action is always active.
More information: ABAP RESTful Application Programming Model - Actions
Search term: #InlineActionInLineItem
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
Inline actions are used to trigger actions directly for a single line item. When declaring an inline action, the action button will show up in the table row within its own column.
The keyword to use for this is inline: true
in @UI.lineItem
, @UI.fieldGroup
, etc in conjunction with an action.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #InlineActionInLineItem
@UI.lineItem: [
{
type:#FOR_ACTION,
label: 'Change Progress(#InlineActionInLineItem)',
dataAction: 'changeProgress',
inline: true,
emphasized: true,
importance: #HIGH,
position: 100
}
]
LastChangedAt;
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
action changeProgress parameter /DMO/FSA_D_ChangeProgressP result [1] $self;
Search term: #CopyActionInLineItem
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
For a deep copy of an instance, the RAP framework does not provide a copy action out of the box, unlike create/edit/delete. However you can define a factory action in the BDEF that copies an instance, and by using the keyword isCopyAction: true
, the action button will be rendered in UI harmoniously with Create/Delete. When no label is provided, it is automatically set to 'Copy'.
The cardinality of a factory action is always [1], that means, only one instance can be copied at a time.
When used in conjunction with inline: true
to render the Copy button at individual line items, a label must be provided by you.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #CopyActionInLineItem
@UI.lineItem: [
{
type:#FOR_ACTION,
dataAction: 'copyInstance',
isCopyAction: true
}
]
LastChangedAt;
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
factory action copyInstance [1];
Search term: #Navigation-IBN
An action navigating to a published app of an associated entity can be added, through Intent Based Navigation using @UI.lineItem
. When the navigation is setup properly, a button will be rendered at the table toolbar. Since this feature requires Fiori Launchpad and a destination app that has been published, the following is just an example of how it can be coded, as this navigation does not work in a FE App Preview.
Here "FeatureShowcaseNavigation" is the semantic object to be referenced.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Tern #Navigation-IBN
@Consumption.semanticObject: 'FeatureShowcaseNavigation'
@UI.lineItem: [
{
label: 'IntentBased Navigation (#NavAction-IBN)',
type: #FOR_INTENT_BASED_NAVIGATION,
semanticObjectAction: 'manage',
requiresContext: true
}
]
NavigationID;
More information: ABAP RESTful Application Programming Model - Based on Intent
Search term: #WithActionInLineItem
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
An action that is tied to a data value, which would be rendered as a hyperlink. Therefore it is crucial to specify the annotation at the desired element which has the data value.
The keyword to use for this is type: #WITH_ACTION
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI: {
lineItem: [
{
position: 50,
criticality: 'CriticalityCode',
label: 'Change Criticality (#WithActionInLineItem)',
type: #WITH_ACTION,
dataAction: 'changeCriticality',
importance: #LOW
}
]
}
FieldWithCriticality;
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
action changeCriticality parameter /DMO/FSA_D_ChangeCriticalityP result [1] $self;
Search term: #PresentationVariant
A presentation variant defines how the result of a queried collection of entities is shaped and how this result is displayed, for example as a list report or a chart (@UI.presentationVariant.visualizations
), the sorting order (@UI.presentationVariant.sortOrder
), or the number of items (@UI.presentationVariant.maxItems
) to display per segment.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #PresentationVariant
@UI.presentationVariant: [
{
qualifier: 'pvariant',
maxItems: 5,
// Search Term #DefaultSort
sortOrder: [
{
by: 'StringProperty',
direction: #ASC
}
],
visualizations: [{type: #AS_LINEITEM}]
}
]
Search term: #SelectionVariant
With a selection variant, you can define how the properties of an entity set should be filtered. The attribute text
of the annotation is the title of the view and the attribute filter
contains all filter parameters.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #SelectionVariant
@UI.selectionVariant: [
{
qualifier: 'svariant',
text: 'Selection (Criticality between 0 and 2)',
filter: 'CriticalityCode GE 0 and CriticalityCode LE 2'
}
]
Search term: #SelectionPresentationVariant
A SelectionPresentationVariant bundles a Selection Variant and a Presentation Variant.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.presentationVariant: [
{
qualifier: 'pvariant',
maxItems: 5,
// Search Term #DefaultSort
sortOrder: [
{
by: 'StringProperty',
direction: #ASC
}
],
visualizations: [{type: #AS_LINEITEM}]
}
]
@UI.selectionVariant: [
{
qualifier: 'svariant',
text: 'Selection (Criticality between 0 and 2)',
filter: 'CriticalityCode GE 0 and CriticalityCode LE 2'
}
]
// Search Term #SelectionPresentationVariant
@UI.selectionPresentationVariant: [
{
text: 'SPresVariant (Criticality between 0 and 2)',
presentationVariantQualifier: 'pvariant',
selectionVariantQualifier: 'svariant'
}
]
Search term: #DefaultSort
Use the @UI.presentationVariant
annotation to define a default sort order. The attribute by
defines, on which property the sort order should be applied.
Without a sort order defined with direction
, the values are ascending.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.presentationVariant: [
{
// Search Term #DefaultSort
sortOrder: [
{
by: 'StringProperty',
direction: #ASC
}
],
visualizations: [{type: #AS_LINEITEM}]
}
]
Search term: #LineItemHighlight
Line items can be highlighted based on criticality. The @UI.lineItem
annotation should be annotated at Entity level.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #LineItemHighlight
@UI.lineItem: [{criticality: 'CriticalityCode'}] // Annotation, so that the line item row has a criticality
Search term: #DataPointRatingTable
To add a rating indicator (stars) to the table, you first need to define a datapoint with @UI.dataPoint
. The property where datapoint is defined sets how many stars are visible. Values between x.25 and x.74 are displayed as a half star. The attribute targetValue
defines how many stars are possible. Most importantly, the qualifier needs to match the property name.
To show it in the table, @UI.lineItem
annotation is needed.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI: {
// Search Term #DataPointRating, #DataPointRatingTable
dataPoint: {
qualifier: 'StarsValue',
targetValue: 4,
visualization: #RATING,
title: 'Rating Indicator (#DataPointRating)'
},
// Search Term #DataPointRatingTable
lineItem: [
{
type: #AS_DATAPOINT,
label: 'Rating Indicator (#DataPointRatingTable)',
importance: #LOW,
position: 70
}
]
}
StarsValue;
Example: ABAP RESTful Application Programming Model - Develop Node Extensions - Extension Node with Rating
Search term: #DataPointProgressTable
To add a progress indicator to the table, you first need to define a datapoint with @UI.dataPoint
. The property where datapoint is defined sets the current progress and the attribute targetValue
, the maximum progress. Additionally, a criticality can be given, if wanted. Most importantly, the qualifier needs to match the property name.
To show it in the table, @UI.lineItem
annotation is needed.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #DataPointProgress, #DataPointProgressTable
@UI: {
dataPoint: {
qualifier: 'ProgressIntegerValue',
targetValue: 100,
visualization: #PROGRESS,
criticality: 'CriticalityCode',
title: 'Progress Indicator (#DataPointProgress)'
},
// Search Term #DataPointProgressTable
lineItem: [
{
type:#AS_DATAPOINT,
label: 'Progress Ind. (#DataPointProgressTable)',
importance: #LOW,
position: 60
}
]
}
ProgressIntegerValue;
Example: ABAP RESTful Application Programming Model - Develop Node Extensions - Extension Node with Progress
Search term: #BulletMicroChartTable
To add a bullet micro chart to a table you have to first define a data point at the property where the value is to be taken from, which is the actual bar. The following attributes are also mandatory: minimumValue
to render the chart properly, forecastValue
for the bar in the background with a lower opacity, targetValue
(or targetValueElement
) for the dark line and qualifier
(qualifier must be set to the name of the property). Criticality is optional.
To show the chart, the property must then be annotated with @UI.lineItem
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
/// Search Term: #BulletMicroChart, #BulletMicroChartTable
@UI: {
dataPoint: {
qualifier: 'IntegerValue', //IntegerValue: horizontal bar in relation to the goal line
targetValueElement: 'TargetValue', //visual goal line in the UI
forecastValue: 'ForecastValue', //horizontal bar behind the value bar with, slightly larger with higher transparency
criticality: 'CriticalityCode',
minimumValue: 0 //Minimal value, needed for output rendering
},
// Search Term #BulletMicroChartTable
lineItem: [{
type:#AS_CHART,
label: 'Bullet Chart (#BulletMicroChartTable)',
valueQualifier: 'bulletChart',
importance: #HIGH,
position: 80
}]
}
IntegerValue;
The data point needs to be referenced in a @UI.chart
annotation in the measure attributes. The chartType
must have value #BULLET
for a bullet chart, attributes measures
and measureAttributes
are mandatory.
// Search Term #BulletMicroChart, #BulletMicroChartTable
@UI.chart: [
{
qualifier: 'bulletChart',
title: 'Bullet Micro Chart (#BulletMicroChart)',
description: 'This is a micro chart',
chartType: #BULLET,
measures: ['IntegerValue'],
measureAttributes: [
{
measure: 'IntegerValue',
role: #AXIS_1,
asDataPoint: true
}
]
}
]
Search term: #RadialMicroChartTable
To add a radial micro chart to a table you have to first define a data point at the property where the value is to be taken from. The percentage value is the fraction of the property value and the target value, which is set in attribute targetValue
(or targetValueElement
). Both criticality
and criticalityCalculation
are supported, but if both are given criticality
overrides criticalityCalculation
. Qualifier must be set to the name of the property.
To show the chart, the property must then be annotated with @UI.lineItem
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #RadialMicroChart, #RadialMicroChartTable
@UI: {
dataPoint: {
qualifier: 'RadialIntegerValue',
targetValueElement: 'TargetValue', //The relation between the value and the target value will be displayed as a percentage
criticality: 'CriticalityCode'
},
// Search Term #RadialMicroChartTable
lineItem: [
{
type: #AS_CHART,
label: 'Radial Chart (#RadialMicroChartTable)',
valueQualifier: 'radialChart',
position: 110
}
]
}
RadialIntegerValue;
The data point needs to be referenced in a @UI.chart
annotation in the measure attributes. The chartType
must have value #Donut
for a radial chart, attributes measures
and measureAttributes
are mandatory.
// Search Term #RadialMicroChart, #RadialMicroChartTable
@UI.chart: [
{
qualifier: 'radialChart',
title: 'Radial Micro Chart (#RadialMicroChart)',
description: 'This is a micro chart',
chartType: #DONUT,
measures: ['RadialIntegerValue'],
measureAttributes: [
{
measure: 'RadialIntegerValue',
role: #AXIS_1,
asDataPoint: true
}
]
}
]
Search term: #ContactInHeader, #ContactInLineItem, #Contact
To have a data field which shows a contact with a contact quick view, the contact quick view needs to be implemented first. An example would be:
Note
Source: CDS View /DMO/FSA_I_Contact
// Search Term #Contact
define view entity /DMO/FSA_I_Contact
{
@ObjectModel.text.element: ['Name'] // Search Term #DisplayTextAndID
key id as ID,
@Semantics.name.fullName: true
name as Name,
@Semantics.telephone.type: [#PREF]
phone as Phone,
@Semantics.address.country: true
country as Country,
@Semantics.address.street: true
street as Street,
@Semantics.address.city: true
city as City,
@Semantics.address.zipCode: true
postcode as Postcode,
@Semantics.address.label: true
address_label as AddressLabel
}
To show the contact card in the table you need to annotate the contact property with @UI.lineItem
or if in a facet, with @UI.fieldGroup
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
{
purpose : #HEADER, // or #STANDARD
label : 'General Data (#HeaderFieldGroup)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'HeaderData'
}
]
// Search Term #ContactInHeader
@UI.fieldGroup: [
{
qualifier: 'HeaderData',
type: #AS_CONTACT,
label: 'Contact QuickView (#ContactInHeader)',
position: 70,
value: '_Contact'
}
]
// Search Term #ContactInLineItem
@UI.lineItem: [
{
type:#AS_CONTACT,
label: 'Contact QuickView (#ContactInLineItem)',
value: '_Contact',
position: 120
}
]
ContactID;
More Information: ABAP RESTful Application Programming Model - Contact Data
Search term: #QuickViewTable
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
A quick view is a pop up that shows more information, when you click on an entry in a column or an object page. Typically, it is used in combination with one-to-one or zero-to-one associations. By clicking on the link, more information about the associated entity can be displayed.
To set up an entity as QuickView, follow the steps here: Setting up QuickView
To show the QuickView in a table, just use annotation @UI.lineItem
to add the property, with has referential constraint defined, into the table.
// Search Tern #QuickViewTable
@UI.lineItem: [
{
label: 'Navigation (#QuickViewTable)',
importance: #HIGH,
position: 90
}
]
NavigationID;
Search term: #MultiFieldsCol
Multiple fields can be shown in one column, if a field group is added to line item (with annotations @UI.lineItem
and @UI.fieldGroup
). First you must define the field group and secondly the line item.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.fieldGroup: [{ qualifier: 'AdminData' }] // Search Term #MultiFieldsCol
CreatedAt;
@UI.fieldGroup: [{ qualifier: 'AdminData' }] // Search Term #MultiFieldsCol
LocalLastChangedBy;
@UI.fieldGroup: [{ qualifier: 'AdminData' }] // Search Term #MultiFieldsCol
LocalLastChangedAt;
// Search Term #MultiFieldsCol
@UI: {
fieldGroup: [{ qualifier: 'AdminData' }],
lineItem: [
{
type: #AS_FIELDGROUP,
label: 'Admin Data (#MultiFieldsCol)',
valueQualifier: 'AdminData',
importance: #HIGH,
position: 100
}
]
}
CreatedBy;
Search term: #Image
Images are typically the first column in a table and help to visually guide the user. An image can be added to a table by just adding a normal property to the line items.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #Image
@UI.lineItem: [
{
cssDefault.width: '5em',
position: 10,
importance: #HIGH,
label: '(#Image)'
}
]
@EndUserText.quickInfo: '(#Image)'
ImageUrl;
The property which contains the image url has to, additionally, be annotated with @Semantics.imageURL: true
.
Note
Source: CDS View /DMO/FSA_I_Root
@Semantics.imageUrl: true
image_url as ImageUrl,
Search term: #Units
The special thing about quantity or price properties, is that they have an additional property of unit/currency. The property containing the quantity/price should be linked with the property for unit/currency. For units of measure the annotation is @Semantic.quantity.unitOfMeasure
and for currency, it is @Semantic.amount.currencyCode
.
Note
Source: CDS View /DMO/FSA_I_Root
// Search Term #Units
@Semantics.quantity.unitOfMeasure: 'Uom'
field_with_quantity as FieldWithQuantity,
// Search Term #Units
@Semantics.amount.currencyCode: 'IsoCurrency'
field_with_price as FieldWithPrice,
More Information: ABAP RESTful Application Programming Model - Interaction with Other Annotations
Search term: #Stream, #StreamTable
You can enable your RAP application for maintaining large objects (LOBs). By doing so, you provide end users the option to incorporate external binary files or text files when editing entity instances. First the appropriate fields should be added into the database table and the CDS view, and also the annotations @Semantics.largeObject
and @Semantics.mimeType
. To show it in a table, you will need annotation @UI.lineItem
. Lastly, you should also update the mapping and the draft table in your behaviour definition.
Note
Source: Database Table /DMO/FSA_ChildA
stream_filename : abap.char(128);
stream_mimetype : abap.char(128);
stream_file : abap.rawstring(0);
Note
Source: CDS View /DMO/FSA_C_ChildTP
StreamFilename, // Search Term #Stream
// Search Term #Stream
@Semantics.largeObject: {
acceptableMimeTypes: [ 'image/*', 'application/*' ],
cacheControl.maxAge: #MEDIUM,
contentDispositionPreference: #INLINE, // #ATTACHMENT - download as file
// #INLINE - open in new window
fileName: 'StreamFilename',
mimeType: 'StreamMimeType'
}
StreamFile,
// Search Term #Stream
@Semantics.mimeType: true
StreamMimeType,
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #Stream
@UI.hidden: true
StreamMimeType;
@UI.lineItem: [{ position: 40, label: 'Attachment (#StreamTable)' }] // Search Term #StreamTable
StreamFile;
// Search Term #Stream
@UI.hidden: true
StreamFilename;
Note
Source: BDEF /DMO/FSA_R_ROOTTP
define behavior for /DMO/FSA_R_ChildTP alias Child {
...
mapping for /dmo/fsa_child_a {
..
StreamFile = stream_file;
StreamFilename = stream_filename;
StreamMimeType = stream_mimetype;
}
More Information: ABAP RESTful Application Programming Model - Working with Large Objects
Search term: #StreamStaticFeatureCtrl
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
It is possible to enable static field control for your large object property/attachment. This is done by adding the control in the behaviour definition.
In our example, we have set the stream property to readonly.
Note
Source: CDS View /DMO/FSA_C_ChildTP
// Search Term #StreamStaticFeatureCtrl
@Semantics.largeObject: {
acceptableMimeTypes: [ 'image/*', 'application/*' ],
cacheControl.maxAge: #MEDIUM,
contentDispositionPreference: #ATTACHMENT , // #ATTACHMENT - download as file
// #INLINE - open in new window
fileName: 'StreamFilename',
mimeType: 'StreamMimeType'
}
StreamFileReadonly,
StreamFilename,
@Semantics.mimeType: true
StreamMimeType,
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #StreamStaticFeatureCtrl
@UI: {
lineItem: [
{
position: 70,
label: 'Attachment (#StreamStaticFeatureCtrl)'
}
]
}
StreamFileReadonly;
// Search Term #Stream
@UI.hidden: true
StreamMimeType;
// Search Term #Stream
@UI.hidden: true
StreamFilename;
Note
Source: BDEF /DMO/FSA_R_ROOTTP
define behavior for /DMO/FSA_R_ChildTP alias Child .. {
field ( readonly ) StreamFileReadonly; // Search Term #StreamStaticFeatureCtrl
}
More Information: ABAP RESTful Application Programming Model - Static Feature Control
Search term: #StreamDynamicFeatureCtrl
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
It is possible to enable dynamic field control for your large object property/attachment. This is done by adding the control in the behaviour definition.
In our example, we set the stream property to readonly, when the boolean property StreamIsReadOnly
is set to true
. This can only be done when creating a new child instance, as the property StreamIsReadOnly
itself has field control readonly : update, mandatory : create
.
Note
Source: Database Table /DMO/FSA_ChildA
stream_filename : abap.char(128);
stream_mimetype : abap.char(128);
stream_file : abap.rawstring(0);
stream_is_readonly : abap_boolean;
Note
Source: CDS View /DMO/FSA_C_ChildTP
StreamIsReadOnly, // Search Term #StreamDynamicFeatureCtrl
StreamFilename, // Search Term #Stream
// Search Term #Stream
@Semantics.largeObject: {
acceptableMimeTypes: [ 'image/*', 'application/*' ],
cacheControl.maxAge: #MEDIUM,
contentDispositionPreference: #INLINE, // #ATTACHMENT - download as file
// #INLINE - open in new window
fileName: 'StreamFilename',
mimeType: 'StreamMimeType'
}
StreamFile,
// Search Term #Stream
@Semantics.mimeType: true
StreamMimeType,
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #StreamDynamicFeatureCtrl
@UI: {
lineItem: [
{
position: 50,
label: 'Stream readonly? (#StreamDynFeatureCtrl)'
}
]
}
@EndUserText: {
label: 'Stream readonly? Caution - cannot be changed after create',
quickInfo: 'Stream readonly?'
}
StreamIsReadOnly;
// Search Term #Stream
@UI.hidden: true
StreamMimeType;
@UI: {
// Search Term #StreamTable
lineItem: [
{
position: 60,
label: 'Attachment (#StreamTable)'
}
]
}
StreamFile;
// Search Term #Stream
@UI.hidden: true
StreamFilename;
Note
Source: BDEF /DMO/FSA_R_ROOTTP
define behavior for /DMO/FSA_R_ChildTP alias Child ... {
field ( readonly : update, mandatory : create ) StreamIsReadOnly;
...
mapping for /dmo/fsa_child_a {
StreamFile = stream_file;
StreamFilename = stream_filename;
StreamMimeType = stream_mimetype;
}
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_ROOTTP
CLASS lhc_child IMPLEMENTATION.
METHOD get_instance_features.
READ ENTITIES OF /DMO/FSA_R_RootTP IN LOCAL MODE
ENTITY Child
FIELDS ( StreamIsReadOnly )
WITH CORRESPONDING #( keys )
RESULT DATA(children).
result = VALUE #( FOR child IN children
( %tky = child-%tky
%field-StreamFile = COND #( WHEN child-StreamIsReadOnly = abap_true
THEN if_abap_behv=>fc-f-read_only
ELSE if_abap_behv=>fc-f-unrestricted )
) ).
ENDMETHOD.
ENDCLASS.
More Information: ABAP RESTful Application Programming Model - Dynamic Feature Control
Search term: #Navigation-URL
You can set the text of a property as a link to an external website using the annotation @UI.lineItem.type: #WITH_URL
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #Navigation-URL
@UI.lineItem: [
{
url: 'FieldWithUrl', //Target, when pressing the text
label: 'URL Property (#Navigation-URL)',
type: #WITH_URL,
importance: #MEDIUM,
position: 130
}
]
FieldWithUrlText;
More Information: ABAP RESTful Application Programming Model - With URL
Search term: #CommunicationFields
To display emails and phone numbers as a link, they are annotated with @Semantics.email.address: true
or @Semantics.telephone.type
Note
Source: CDS View /DMO/FSA_I_Root
// Search Term #CommunicationFields
@Semantics.eMail.address: true
email as Email,
// Search Term #CommunicationFields
@Semantics.telephone.type: [#CELL]
telephone as Telephone,
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #Communication
@UI.facet: [
{
purpose: #HEADER, // or #STANDARD
label : 'Communication Subsection(#Communication)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'communication'
}
]
@UI.fieldGroup: [{ qualifier: 'communication' }] // Search Term #Communication
Email;
@UI.fieldGroup: [{ qualifier: 'communication' }] // Search Term #Communication
Telephone;
More Information: ABAP RESTful Application Programming Model - Contact Data
Search term: #TimeAndDate
SAP Fiori Elements provides out of the box support for displaying and editing dates and times, as well as time stamps. No additional annotations are needed, the properties just need to have the corresponding data types.
The following annotations are used in the app, in order to group the time and date fields and show them in a facet.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #TimeAndDate
@UI.facet: [
{
purpose: #HEADER, // or #STANDARD
label : 'Time and Date (#TimeAndDate)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'timeAndDate'
}
]
@UI.fieldGroup: [{ qualifier: 'timeAndDate' }] // Search Term #TimeAndDate
ValidTo;
@UI.fieldGroup: [{ qualifier: 'timeAndDate' }] // Search Term #TimeAndDate
Time;
@UI.fieldGroup: [{ qualifier: 'timeAndDate' }] // Search Term #TimeAndDate
Timestamp;
Search term: #MultiLineText
With the annotation @UI.multiLineText
longer strings are displayed in multiple lines.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.multiLineText: true // Search Term #MultiLineText
Description;
@UI.multiLineText: true // Search Term #MultiLineText
DescriptionCustomGrowing;
More Information: ABAP RESTful Application Programming Model - Multi-Line Text
Search term: #CollectiveValueHelp
For SAP GUI-based applications it is possible to define a collective search help that combines several elementary search helps. You can choose one of several alternative search paths and retrieve input values from multiple sources/tables in a single dialog. In Fiori UI this is also possible via a collective value help using an abstract entity comprising a list of assigned elementary search helps and potential mappings of the bound field names.
The collective value help shall be annotated with @ObjectModel.collectiveValueHelp.for.element
pointing to the field, for which the collective value help is defined. The field referenced by @ObjectModel.collectiveValueHelp.for.element
shall be assigned at least a single elementary value help using annotation @Consumption.valueHelpDefinition
.
Only the following keywords can be used for a collective value help: entity.name
, entity.element
, additionalBinding.localElement
, additionalBinding.element
and qualifier
.
Note
Source: CDS Abstract Entity /DMO/FSA_D_CountryCVH
@EndUserText.label: 'Country Collective Value Help'
@ObjectModel.supportedCapabilities:[#COLLECTIVE_VALUE_HELP]
@ObjectModel.modelingPattern:#COLLECTIVE_VALUE_HELP
@ObjectModel.collectiveValueHelp.for.element: 'Country'
// Search Term #CollectiveValueHelp
define abstract entity /DMO/FSA_D_CountryCVH
{
@Consumption.valueHelpDefinition:[
// 'Default' VH
{
entity: { name:'I_Country' },
label: 'Search by Country'
},
// additional VH, set qualifier
{
entity: { name:'/DMO/FSA_I_ContactVH',
element:'Country' },
label: 'Search by Contact',
qualifier: 'ContactSearch'
},
// additional VH, set qualifier
{
entity: { name:'I_RegionVH',
element:'Country' },
additionalBinding: [{ localElement:'Region',
element:'Region' }],
label: 'Search by Region',
qualifier: 'RegionSearch'
}
]
Country : land1;
Region : regio;
}
The consumer view of the collective value help has to define the same fields, that are used in the collective value help definition (respectively bind all corresponding local fields via @Consumption.valueHelpDefinition.additionalBinding... to the collective value help fields).
Note
Source: CDS View /DMO/FSA_R_RootTP
// Search Term #CollectiveValueHelp
@Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/FSA_D_CountryCVH', element: 'Country' },
additionalBinding: [{ element: 'Region',
localElement: 'Region' }] }]
Country,
...
Region,
Search term: #SideEffects, #SideEffectsSection
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
Side Effects annotations specify to the UI, which targets to be refreshed in order to show updated values that arises from field changes, actions, or determine actions. Side effects are defined in the behaviour definition. There are a variety of ways to annotate side effects by combining the triggers and the affected components, and a few examples are shown in the app:
Warning
If you use projection, remember to add the following to your projection behaviour definition.
projection...
use side effects;
define behavior for ProjectionView {
}
Fields from same level entity
When the user changes the value of IntegerValue
, the determination setIntegerValue
is called and modifies the values of ProgressIntegerValue
and RadialIntegerValue
. In order for these 2 fields to show the updated values without a refresh, side effects is required to request UI to reload these 2 fields.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
determination setIntegerValue on modify { field IntegerValue; }
side effects {
field IntegerValue affects field ProgressIntegerValue, field RadialIntegerValue;
}
}
Fields from associated entity
It is also possible to define as target, a field from an assoicated entity. When the field ChildPieces
in Child entity is modified, this will trigger the determination calculateTotalPieces
to total up the pieces of all child instances. Side effects will trigger the refresh of field TotalPieces
from the Root entity to show the calculated total every time user enters a value at the child instance.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_ChildTP alias Child
persistent table /dmo/fsa_child_a
draft table /dmo/fsa_child_d
lock dependent by _Root
authorization dependent by _Root
{
determination calculateTotalPieces on modify { field ChildPieces; }
side effects {
field ChildPieces affects field _Root.TotalPieces;
}
}
When NavigationID
is changed, the associated entity _Navigation
will reload and all fields of the association will change.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
side effects {
field NavigationID affects entity _Navigation;
}
}
When resetTimesChildCreated
is executed, the field TimesChildCreated
will be set to 0.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
action ( features : instance ) resetTimesChildCreated;
side effects {
action resetTimesChildCreated affects field TimesChildCreated;
}
}
When resetTimesChildCreated
is executed, instance feature control will disable the action button resetTimesChildCreated
.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
action ( features : instance ) resetTimesChildCreated;
side effects {
action resetTimesChildCreated affects permissions ( action resetTimesChildCreated );
}
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_RootTP
CLASS lhc_Root DEFINITION INHERITING FROM cl_abap_behavior_handler.
METHOD resetTimesChildCreated.
MODIFY ENTITIES OF /DMO/FSA_R_RootTP IN LOCAL MODE
ENTITY Root
UPDATE
FIELDS ( TimesChildCreated )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
TimesChildCreated = 0
%control-TimesChildCreated = if_abap_behv=>mk-on ) )
FAILED failed
REPORTED reported.
LOOP AT keys ASSIGNING FIELD-SYMBOL(<key>).
APPEND VALUE #( %tky = <key>-%tky
%msg = new_message( id = '/DMO/CM_FSA'
number = 003
severity = if_abap_behv_message=>severity-success )
%action-resetTimesChildCreated = if_abap_behv=>mk-on ) TO reported-root.
ENDLOOP.
ENDMETHOD.
METHOD get_instance_features.
READ ENTITIES OF /DMO/FSA_R_RootTP IN LOCAL MODE
ENTITY Root
FIELDS ( UpdateHidden TimesChildCreated ) WITH CORRESPONDING #( keys )
RESULT DATA(roots)
FAILED failed.
result = VALUE #( FOR root IN roots
( %tky = root-%tky
%action-resetTimesChildCreated = COND #( WHEN root-UpdateHidden = abap_true OR root-TimesChildCreated = 0
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
) ).
ENDMETHOD.
ENDCLASS.
When createChildFromRoot
is executed, a new Child instance is created. Since the associated entity _Child
is a list table, the list will reload to also show the newly created instance.
Note
Source: Behaviour Definition /DMO/FSA_C_RootTP
define behavior for /DMO/FSA_C_RootTP alias Root
{
action ( features : instance ) createChildFromRoot result [0..1] entity /DMO/FSA_C_ChildTP;
side effects {
action createChildFromRoot affects entity _Child;
}
}
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
annotate entity /DMO/FSA_C_RootTP with
{
@UI.facet: [
{
purpose: #STANDARD,
type: #PRESENTATIONVARIANT_REFERENCE,
targetElement: '_Child',
targetQualifier: 'pVariant',
label: 'Child Entity (1..n)(#OPTable)',
id: 'childEntitiesSection'
}
]
...
}
When field ValidTo
is modified, this will trigger the determine action, which is a validation in this case. Any error messages arising from the validation will pop up immediately via sticky messages.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
validation validateValidTo on save { create; update; field ValidTo; }
determine action validateDate { validation validateValidTo; }
side effects {
determine action validateDate executed on field ValidTo affects messages;
}
}
When any fields from entity _Child
is modified, this will trigger the determine action, which is a validation defined at Child. Any error messages arising from the validation will pop up immediately via sticky messages.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
determine action validateChild { validation Child ~ validatePercentage; }
side effects {
determine action validateChild executed on entity _Child affects messages;
}
}
define behavior for /DMO/FSA_R_ChildTP alias Child
...
{
validation validatePercentage on save { create; update; }
}
When any fields from $self is modified, the permission/feature control of the association will be refreshed. In our example, when the boolean property DisableChildOperation
is checked, the list of child instances will be refreshed and update is disabled.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
{
side effects {
$self affects permissions ( update _Child );
}
}
define behavior for /DMO/FSA_R_ChildTP alias Child
...
{
update (features : instance);
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_RootTP
CLASS lhc_child DEFINITION INHERITING FROM cl_abap_behavior_handler.
METHOD get_instance_features.
READ ENTITIES OF /DMO/FSA_R_RootTP IN LOCAL MODE
ENTITY Child BY \_Root
FIELDS ( DisableChildOperation )
WITH CORRESPONDING #( keys )
RESULT DATA(roots)
ENTITY Child
FIELDS ( BooleanProperty )
WITH CORRESPONDING #( keys )
RESULT DATA(children).
DATA(lv_boolean) = roots[ 1 ]-DisableChildOperation.
result = VALUE #( FOR child IN children
( %tky = child-%tky
%update = COND #( WHEN lv_boolean = abap_true
THEN if_abap_behv=>fc-o-disabled
ELSE if_abap_behv=>fc-o-enabled )
) ).
ENDMETHOD.
ENDCLASS.
When an instance of an associated entity is deleted, a field should be updated. While there is no dedicated syntax to cater for this use case, this can be achieved with a workaround by defining a determination that is always called by a determine action, with side effect defined for the determine action.
In our example, updating ChildPieces
at the associated entity _Child
will update the field TotalPieces
of the Root
entity.
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
define behavior for /DMO/FSA_R_RootTP alias Root
...
determination updateTimesChildCreated on save { create; }
determine action updateTimes { determination ( always ) updateTimesChildCreated; }
{
side effects {
determine action updateTimes executed on entity _Child affects field TotalPieces;
}
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_RootTP
METHOD updateTimesChildCreated.
READ ENTITIES OF /DMO/FSA_R_RootTP IN LOCAL MODE
ENTITY Root BY \_Child
FIELDS ( ChildPieces ) WITH CORRESPONDING #( keys )
RESULT DATA(children).
MODIFY ENTITIES OF /DMO/FSA_R_RootTP IN LOCAL MODE
ENTITY Root
UPDATE
FIELDS ( TotalPieces )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
TotalPieces = REDUCE i( INIT val TYPE i
FOR child IN children
NEXT val += child-ChildPieces )
%control-TotalPieces = if_abap_behv=>mk-on ) )
FAILED DATA(upd_failed)
REPORTED DATA(upd_reported).
reported = CORRESPONDING #( DEEP upd_reported ).
ENDMETHOD.
More Information:
Search term: #DatapointHidden
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
If you are showing data points in the sections of your object page, it is possible to hide them using annotation @UI.datapoint.hidden
, either with a constant true
or with a reference to a boolean property.
In this example, Email
and Telephone
will be hidden when the root instance is not updateable.
Caution
There is a limitation with using this annotation at the header section. Refer to Constraints
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
annotate entity /DMO/FSA_C_RootTP with
{
@UI.facet: [
// Search Term #DatapointHidden
{
purpose: #STANDARD,
type: #COLLECTION,
label: 'Communication (#DatapointHidden)',
id: 'datapointHidden',
parentId: 'Nested'
},
{
parentId: 'datapointHidden',
type: #DATAPOINT_REFERENCE,
targetQualifier: 'Email'
},
{
parentId: 'datapointHidden',
type: #DATAPOINT_REFERENCE,
targetQualifier: 'Telephone'
}
]
...
UpdateHidden;
// Search Term #DatapointHidden
@UI.dataPoint: {
title: 'Email (#DatapointHidden)',
qualifier: 'Email',
hidden: #(UpdateHidden)
}
@EndUserText.label: 'Email (#DatapointHidden)'
Email;
// Search Term #DatapointHidden
@UI.dataPoint: {
title: 'Telephone (#DatapointHidden)',
qualifier: 'Telephone',
hidden: #(UpdateHidden)
}
@EndUserText.label: 'Telephone (#DatapointHidden)'
Telephone;
}
Search term: #HeaderInfo
The title and subtitle of an Object Page are defined with the annotation @UI.headerInfo
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #HeaderInfo
@UI.headerInfo: {
typeName: 'Object Page - Root',
typeNamePlural: 'Root Entities (#ListTableTitle)', // Search Term #ListTableTitle
typeImageUrl: 'sap-icon://sales-order',
imageUrl: 'ImageUrl',
title: {
value: 'StringProperty',
type: #STANDARD
},
description: {
label: 'Root entity',
type: #STANDARD,
value: 'StringProperty'
}
}
The attribute typeName
is the title and it is displayed next to the SAP Logo in header bar on the Object Page. The attribute typeNamePlural
will be shown, if all entities are shown in a table. The attribute title
is displayed as the header in the Object Page in bold. Attribute description
is shown beneath title
and if the optional imageUrl
is given, then the picture will be visible on the left side of the title
and description
. If no url is given for the imageUrl
, but typeImageUrl
is defined, it will be displayed instead.
More Information:
- ABAP RESTful Application Programming Model - Defining the Table Header of a List Report
- ABAP RESTful Application Programming Model - Defining the Title Section of an Object Page
Search term: #HeaderFacet
The header facet is displayed in the header of an Object Page. The facet is annotated with UI.facet.purpose: #HEADER
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// OPHEADER
// Search Term #HeaderFacet, #KeyValue
{
purpose: #HEADER,
type: #DATAPOINT_REFERENCE,
targetQualifier: 'fieldWithPrice'
}
]
// Search Term #HeaderFacet, #KeyValue
@UI.dataPoint: {
qualifier: 'fieldWithPrice',
title: 'Field with Price (#HeaderFacet)'
}
FieldWithPrice;
More Information: ABAP RESTful Application Programming Model - Using Facets to change the Object Page Layout
Search term: #HeaderFieldGroup
, #ContactInHeader
, #OPQuickView
Field groups can be part of a header.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #HeaderFieldGroup
@UI.facet: [
{
purpose: #HEADER
label : 'General Data (#HeaderFieldGroup)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'HeaderData'
}
]
A quick view contact card can be displayed (#ContactInHeader). A QuickView can be displayed by just adding the property as a data field (#OPQuickView). Both implementations are identical to how they would be added as a line item in a List Report:
// Search Term #HeaderFieldGroup
@UI.fieldGroup: [
{
qualifier: 'HeaderData',
position: 10,
label: 'Field with Sem. Key(#SemanticKey)'
}
]
StringProperty;
// Search Term #ContactInHeader, #HeaderFieldGroup
@UI.fieldGroup: [
{
qualifier: 'HeaderData',
type: #AS_CONTACT,
label: 'Contact QuickView (#ContactInHeader)',
position: 70,
value: '_Contact'
}
]
ContactID;
// Search Term #HeaderFieldGroup, #WithAction
@UI.fieldGroup: [
{
qualifier: 'HeaderData',
criticality: 'CriticalityCode',
position: 20,
label: 'Change Criticality (#WithAction)',
dataAction: 'changeCriticality',
type: #WITH_ACTION
}
]
FieldWithCriticality;
// Search Term #HeaderFieldGroup, #OPQuickView
@UI.fieldGroup: [
{
qualifier: 'HeaderData',
position: 50,
label: 'Navigation QuickView (#OPQuickView)'
}
]
NavigationID;
Search term: #SemanticKey
Semantic Key fields can be defined, with the annotation @ObjectModel.semanticKey
, which consists of an array of properties from the entity. The given fields will be displayed in bold, and when possible the editing status will be displayed.
Note
Source: CDS View /DMO/FSA_R_RootTP
// Search Term #SemanticKey
@ObjectModel.semanticKey: ['StringProperty']
Search term: #PlainText
Plain text can be displayed, by adding a standard property to a field group and using this field group as a target of a reference facet.
The property in the field group can be optionally annotated with @UI.MultiLineText
, especially if you have a long text and would like it to be show in the UI as a multi-line text, with an expand/collapse button.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #PlainText
@UI.facet: [
{
purpose: #HEADER,
type: #FIELDGROUP_REFERENCE,
label: 'Plain Text (#PlainText)',
targetQualifier: 'plainText'
}
]
@UI: {
// Search Term #PlainText
fieldGroup: [ { qualifier: 'plainText' } ]
// Search Term #MultiLineText
multiLineText: true
}
Description;
More Information: ABAP RESTful Application Programming Model - Grouping Fields
Search term: #AddressFacet
The property of an entity annotated with @Semantics.address.label
can be directly displayed in an address facet, with target qualifier 'pref' if no specific qualifier is set. The label will be used as is, therefore it needs to be fully formatted. Linebreaks can be achieved with '\n'.
Note
Source: CDS View /DMO/FSA_I_Contact
// Search Term #CONTACT
define view entity /DMO/FSA_I_Contact
...
{
...
@Semantics.address.label: true
@Consumption.valueHelpDefault.display:false
address_label as AddressLabel,
}
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #AddressFacet
@UI.facet: [
{
purpose: #HEADER, // or #STANDARD
label : 'Address (#AddressFacet)',
type : #ADDRESS_REFERENCE,
targetElement: '_Contact',
targetQualifier: 'pref'
}
]
Search term: #DataPointRating
To add a rating indicator (stars) to the object page header, you first need to define a datapoint with @UI.dataPoint
. The property where datapoint is defined sets how many stars are visible. Values between x.25 and x.74 are displayed as a half star. The attribute targetValue
defines how many stars are possible. Most importantly, the qualifier needs to match the property name.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI: {
// Search Term #DataPointRating, #DataPointRatingTable
dataPoint: {
qualifier: 'StarsValue',
targetValue: 4,
visualization: #RATING,
title: 'Rating Indicator (#DataPointRating)'
}
}
StarsValue;
After creating the data point, it has to be added to the @UI.facet
annotation.
@UI.facet: [
{
// Search Term #DataPointRating
purpose: #HEADER, // or #STANDARD
type : #DATAPOINT_REFERENCE,
targetQualifier: 'StarsValue'
}
]
Example: ABAP RESTful Application Programming Model - Develop Node Extensions - Extension Node with Rating
Search term: #DataPointProgress
To add a progress indicator to the object page header, you first need to define a datapoint with @UI.dataPoint
. The property where datapoint is defined sets the current progress and the attribute targetValue
, the maximum progress. Additionally, a criticality can be given, if wanted. Most importantly, the qualifier needs to match the property name.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #DataPointProgress, #DataPointProgressTable
@UI: {
dataPoint: {
qualifier: 'ProgressIntegerValue',
targetValue: 100,
visualization: #PROGRESS,
criticality: 'CriticalityCode',
title: 'Progress Indicator (#DataPointProgress)'
}
}
ProgressIntegerValue;
After creating the data point, it has to be added to the @UI.facet
annotation.
@UI.facet: [
{
// Search Term #DataPointProgress
purpose: #HEADER, // or #STANDARD
type : #DATAPOINT_REFERENCE,
targetQualifier: 'ProgressIntegerValue'
}
]
Example: ABAP RESTful Application Programming Model - Develop Node Extensions - Extension Node with Progress
Search term: #KeyValue
A key value is the default data point, when the attribute visualization
is not specified in @UI.dataPoint
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search Term #Headerfacet, #KeyValue
{
purpose: #HEADER,
type: #DATAPOINT_REFERENCE,
targetQualifier: 'fieldWithPrice'
}
]
@UI: {
// Search Term #HeaderFacet, #KeyValue
dataPoint: {
qualifier: 'fieldWithPrice',
title: 'Field with Price (#HeaderDataPoint)'
}
}
FieldWithPrice;
The following micro charts are supported: Area, Bullet, Radial, Column, Line, Harvey, Stacked bar and Comparison. Micro charts can only be displayed in the header.
A micro chart is defined with the @UI.chart
annotation, which then is the target of a ReferenceFacet in the @UI.facet
of purpose: #HEADER
. The title of the facet is the attribute title
of the annotation and the subtitle is description
. If the property of the data point is a property with unit of measure, the unit will be displayed in the footer. The attribute measures
of the chart has to be a data point.
The @UI.dataPoint
supports generally the attributes criticality
and criticalityCalculation
, but the support varies between the micro chart types. If the value of the data point is annotated with a unit of measure, the unit will be shown as the footer of the micro chart facet.
In the following examples, all used attributes are mandatory.
Search term: #AreaMicroChart
The area micro chart is a trend chart, which provides information for the actual and target value for a specified dimension. The displayed values at the bottom of the chart are the boundary values of the dimension. The values above the chart are the boundary values of the measure attribute.
Note
Source: Metadata Extension /DMO/FSA_C_ChartTP
@UI.chart: [
// Search Term #AreaMicroChart
{
qualifier: 'areaChart',
title: 'Area Micro Chart (#AreaMicroChart)',
description: 'This is a micro chart',
chartType: #AREA,
dimensions: ['Dimensions'],
measures: ['IntegerValueForAreaChart'],
measureAttributes: [
{
measure: 'IntegerValueForAreaChart',
role: #AXIS_1,
asDataPoint: true
}
]
}
]
The criticality calculation of the data point is mandatory, as each value is shown with its threshold (error, warning, acceptance and good) ranges.
// Search Term #AreaMicroChart
@UI.dataPoint: {
qualifier: 'IntegerValueForAreaChart',
targetValueElement: 'TargetValue',
criticalityCalculation: {
improvementDirection: #TARGET,
toleranceRangeLowValueElement: 'AreachartTolLowerboundValue',
toleranceRangeHighValueElement: 'AreachartTolUpperboundValue',
deviationRangeHighValueElement: 'AreachartDevUpperboundValue',
deviationRangeLowValueElement: 'AreachartDevLowerboundValue'
}
}
IntegerValueForAreaChart;
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #AreaMicroChart
@UI.facet: [
{
purpose: #HEADER,
type : #CHART_REFERENCE,
targetQualifier: 'areaChart',
targetElement: '_Chart'
}
]
More Information: ABAP RESTful Application Programming Model: Visualizing Data with Charts
Search term: #BulletMicroChart
The bullet chart features a single measure and compares it to one or more other measures (e.g. value with target comparison). Both criticality
and criticalityCalculation
are supported, but if both are given criticality
overrides criticalityCalculation
. The bullet chart does not support the criticality value of 5 (new item). The measuresAttributes
, while it is mandatory, has no effect on the chart as the values come from datapoint.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
Chart
// Search Term #BulletMicroChart, #BulletMicroChartTable
@UI.chart: [
{
qualifier: 'bulletChart',
title: 'Bullet Micro Chart (#BulletMicroChart)',
description: 'This is a micro chart',
chartType: #BULLET,
measures: ['IntegerValue'],
measureAttributes: [
{
measure: 'IntegerValue',
role: #AXIS_1,
asDataPoint: true
}
]
}
]
Facet
// Search Term #BulletMicroChart
@UI.facet: [
{
purpose: #HEADER,
type : #CHART_REFERENCE,
targetQualifier: 'bulletChart'
}
]
Data Point. The attribute minimumValue
is needed to render the chart properly. The value is the actual bar. The forecastValue
is the bar in the background with a lower opacity and the targetValue
is the dark line. Qualifier must be set to the name of the property.
// Search Term: #BulletMicroChart
@UI.dataPoint: {
qualifier: 'IntegerValue', //IntegerValue: horizontal bar in relation to the goal line
targetValueElement: 'TargetValue', //visual goal line in the UI
forecastValue: 'ForecastValue', //horizontal bar behind the value bar with, slightly larger with higher transparency
criticality: 'CriticalityCode',
minimumValue: 0 //Minimal value, needed for output rendering
}
IntegerValue;
More Information: ABAP RESTful Application Programming Model: Visualizing Data with Charts
Search term: #RadialMicroChart
The radial micro chart displays a single percentage value. The measureAttributes
, while mandatory, has no effect on the chart as the values come from datapoint.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
Chart
// Search Term #RadialMicroChart
@UI.chart: [
{
qualifier: 'radialChart',
title: 'Radial Micro Chart (#RadialMicroChart)',
description: 'This is a micro chart',
chartType: #DONUT,
measures: ['RadialIntegerValue'],
measureAttributes: [
{
measure: 'RadialIntegerValue',
role: #AXIS_1,
asDataPoint: true
}
]
}
]
Facet
// Search Term #RadialMicroChart
@UI.facet: [
{
purpose: #HEADER,
type : #CHART_REFERENCE,
targetQualifier: 'radialChart'
}
]
Data Point. The percentage value is the fraction of the property value and the target value. The unit of measure label will not be rendered, as the chart displays percentage values. Both criticality
and criticalityCalculation
are supported, but if both are given criticality
overrides criticalityCalculation
. Qualifier must be set to the name of the property.
// Search Term #RadialMicroChart
@UI.dataPoint: {
qualifier: 'RadialIntegerValue',
targetValueElement: 'TargetValue', //The relation between the value and the target value will be displayed as a percentage
criticality: 'CriticalityCode'
}
RadialIntegerValue;
More Information: ABAP RESTful Application Programming Model: Visualizing Data with Charts
Search term: #LineMicroChart
The line chart displays a series of data points as a line. The bottom values are the border values of the dimension
. The upper left value is the smallest value of the first measures
property and the upper right value is the largest value of the last measures
property. The shown unit of measure is from the first entry.
Note
Source: Metadata Extension /DMO/FSA_C_ChartTP
// Search Term #LineMicroChart
@UI.chart: [
{
qualifier: 'lineChart',
title: 'Line Micro Chart (#LineMicroChart)',
description: 'This is a micro chart',
chartType: #LINE,
measures: ['IntegerValueForLineChart', 'TargetValue'],
dimensions: ['Dimensions'],
measureAttributes: [
{
measure: 'IntegerValueForLineChart',
role: #AXIS_2,
asDataPoint: true
},
{
measure: 'TargetValue',
role: #AXIS_2,
asDataPoint: true
}
]
}
]
Data Points. It is recommended to only use one measure, and a maximum of three measures, if more is required. If the attribute criticality
contains a path, then the value of the last data point's criticality
determines the color of the line.
// Search Term #LineMicroChart
@UI: {
dataPoint: {
qualifier: 'TargetValue',
criticality: 'CriticalityCode'
}
}
TargetValue;
// Search Term #LineMicroChart
@UI.dataPoint: {
qualifier: 'IntegerValueForLineChart',
criticality: 'CriticalityCode'
}
IntegerValueForLineChart;
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #LineMicroChart
@UI.facet: [
{
purpose: #HEADER,
type: #CHART_REFERENCE,
targetQualifier: 'lineChart',
targetElement: '_Chart'
}
]
More Information: ABAP RESTful Application Programming Model: Visualizing Data with Charts
Search term: #ColumnMicroChart
A column chart uses vertical bars to compare values of a dimension. The displayed values at the bottom of the chart are the boundary values of the dimensions
. The values above the chart are the boundary values of the measureAttributes
.
Note
Source: Metadata Extension /DMO/FSA_C_ChartTP
// Search Term #ColumnMicroChart
@UI.chart: [
{
qualifier: 'columnChart',
title: 'Column Micro Chart (#ColumnMicroChart)',
description: 'This is a micro chart',
chartType: #COLUMN,
measures: ['IntegerValueForOtherCharts'],
dimensions: ['Dimensions'],
measureAttributes: [
{
measure: 'IntegerValueForOtherCharts',
role: #AXIS_1,
asDataPoint: true
}
]
}
]
Data Point. Both criticality
and criticalityCalculation
are supported, but if both are given criticality
overrides criticalityCalculation
.
// Search Term #ColumnMicroChart, #StackedBarMicroChart, #ComparisonMicroChart
@UI.dataPoint: {
qualifier: 'IntegerValueForOtherCharts',
criticality: 'CriticalityCode'
}
IntegerValueForOtherCharts;
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #ColumnMicroChart
@UI.facet: [
{
purpose: #HEADER,
type: #CHART_REFERENCE,
targetQualifier: 'columnChart',
targetElement: '_Chart'
}
]
More Information: ABAP RESTful Application Programming Model: Visualizing Data with Charts
Search term: #HarveyMicroChart
A harvey chart plots a single measure value against a maximum value.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
Chart
// Search Term #HarveyMicroChart
@UI.chart: [
{
qualifier: 'harveyChart',
title: 'Harvey Micro Chart (#HarveyMicroChart)',
description: 'This is a micro chart',
chartType: #PIE,
measures: ['HarveyFieldWithPrice'],
measureAttributes: [
{
measure: 'HarveyFieldWithPrice',
role: #AXIS_1,
asDataPoint: true
}
]
}
]
Data Point. For the semantic coloring, only the attribute criticality
is supported.
//Search-Term: #HarveyMicroChart
@UI.dataPoint: {
qualifier: 'HarveyFieldWithPrice',
maximumValue: 5000,
criticality: 'CriticalityCode'
}
HarveyFieldWithPrice;
Facet
// Search Term #HarveyMicroChart
@UI.facet: [
{
purpose: #HEADER,
type: #CHART_REFERENCE,
targetQualifier: 'harveyChart'
}
]
More Information: ABAP RESTful Application Programming Model: Visualizing Data with Charts
Search term: #StackedBarMicroChart
A stacked bar chart uses vertical bars to compare values of a dimension. The displayed values at the bottom of the chart are the boundary values of the dimensions
. The values above the chart are the boundary values of the measureAttributes
.
Note
Source: Metadata Extension /DMO/FSA_C_ChartTP
// Search Term #StackedBarMicroChart
@UI.chart: [ {
qualifier: 'stackedBarChart',
title: 'StackedBar Micro Chart (#StackedBarMicroChart)',
description: 'This is a micro chart',
chartType: #BAR_STACKED,
measures: ['IntegerValueForOtherCharts'],
dimensions: ['Dimensions'],
measureAttributes: [
{
measure: 'IntegerValueForOtherCharts',
role: #AXIS_1,
asDataPoint: true
}
]
}]
Data Point. Both criticality
and criticalityCalculation
are supported, but if both are given criticality
overrides criticalityCalculation
.
// Search Term #ColumnMicroChart, #StackedBarMicroChart, #ComparisonMicroChart
@UI.dataPoint: {
qualifier: 'IntegerValueForOtherCharts',
criticality: 'CriticalityCode'
}
IntegerValueForOtherCharts;
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #StackedBarMicroChart
@UI.facet: [
{
purpose: #HEADER,
type: #CHART_REFERENCE,
targetQualifier: 'stackedBarChart',
targetElement: '_Chart'
}
]
More Information: ABAP RESTful Application Programming Model: Visualizing Data with Charts
Search term: #ComparisionMicroChart
A comparison chart uses three horizontal bars to compare values of a dimension. If more values are defined in dimensions
, they will only show up in the tooltip. The displayed values on the left represent the dimension value of each data point. The values on the right are the actual values. If a unit of measure is shown, then it is from the first data point to be plotted.
Note
Source: Metadata Extension /DMO/FSA_C_ChartTP
// Search Term #ComparisonMicroChart
@UI.chart: [
{
qualifier: 'comparisonChart',
title: 'Comparison Micro Chart (#ComparisonMicroChart)',
description: 'This is a micro chart',
chartType: #BAR,
measures: ['IntegerValueForOtherCharts'],
dimensions: ['Dimensions'],
measureAttributes: [
{
measure: 'IntegerValueForOtherCharts',
role: #AXIS_1,
asDataPoint: true
}
]
}
]
Data Point. For semantic coloring, only the attribute criticality
is supported.
// Search Term #ColumnMicroChart, #StackedBarMicroChart, #ComparisonMicroChart
@UI.dataPoint: {
qualifier: 'IntegerValueForOtherCharts',
criticality: 'CriticalityCode'
}
IntegerValueForOtherCharts;
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #ComparisonMicroChart
@UI.facet: [
{
purpose: #HEADER,
type: #CHART_REFERENCE,
targetQualifier: 'comparisonChart',
targetElement: '_Chart'
}
]
More Information: ABAP RESTful Application Programming Model: Visualizing Data with Charts
Search term: #OPCopyAction
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
For a deep copy of an instance, the RAP framework does not provide a copy action out of the box, unlike create/edit/delete. However you can define a factory action in the BDEF that copies an instance, and by using the keyword isCopyAction: true
, the action button will be rendered in UI harmoniously with Edit/Delete.
The cardinality of a factory action is always [1], that means, only one instance can be copied at a time.
When no label is provided, it is automatically set to 'Copy'.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.identification: [
// Search Term #OPCopyAction
{
type:#FOR_ACTION,
dataAction: 'copyInstance',
isCopyAction: true
}
]
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
factory action copyInstance [1];
Search term: #OPHeaderAction
Actions for the Object Page in general are annotated using @UI.identification
. The criticality only supports the values 0 (normal), 1 (red) and 3 (green). For normal actions the Object Page content is passed and for static actions, no context is passed.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #OPHeaderAction
@UI.identification: [
{
type: #FOR_ACTION, //Action in the RootEntities of the object page next to the edit button
label: 'Change Criticality (#OPHeaderAction)',
criticality: 'CriticalityCode',
criticalityRepresentation: #WITH_ICON,
dataAction: 'changeCriticality'
}
]
ID;
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
action changeCriticality parameter /DMO/FSA_D_ChangeCriticalityP result [1] $self;
More Information: ABAP RESTful Application Programming Model: Action Implementation - UI Consumption of actions
Search term: #DynamicCRUD
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
The visibility of the "Edit", "Create" and "Delete" buttons in the Object Page can be dynamically adjusted. For example the delete operation can be dependent on a property of the entity, through the annotation @UI.deleteHidden
. Fixed values true or false are also possible.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #DynamicCRUD
@UI.updateHidden: #(UpdateHidden)
@UI.deleteHidden: #(DeleteHidden)
Search term: #WithActionInOP
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
An action that is tied to a data value, which would be rendered as a hyperlink. Therefore it is crucial to specify the annotation at the desired element which has the data value.
The keyword to use for this is type: #WITH_ACTION
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search Term #HeaderCollectionFacet
{
purpose: #HEADER,
id: 'FacetCollection',
type: #COLLECTION
},
// Search Term #HeaderFieldGroup
{
parentId : 'FacetCollection',
label : 'General Data (#HeaderFieldGroup)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'HeaderData'
}
]
@UI: {
fieldGroup: [
// Search Term #HeaderFieldGroup, #WithActionInOP
{
qualifier: 'HeaderData',
criticality: 'CriticalityCode',
position: 30,
label: 'Change Criticality (#WithActionInOP)',
dataAction: 'changeCriticality',
type: #WITH_ACTION
}
]
}
FieldWithCriticality;
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
action changeCriticality parameter /DMO/FSA_D_ChangeCriticalityP result [1] $self;
Multiple sub tabs can be placed underneath a main tab, called nesting. User can click on an expand button to show a drop down list of sub tabs. All that is needed is to define a Collection facet (main tab) and assign other Collection facets (the sub tabs) to it.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search Term #NestedTabs (Main Tab)
{
purpose: #STANDARD,
type: #COLLECTION,
label: 'Nested Tabs (#NestedTabs)',
id: 'Nested'
},
// Search Term #OPSection (Sub tab, take note of parentID)
{
purpose: #STANDARD,
type: #COLLECTION,
label: 'Collection Facet (#OPSection)',
id: 'collectionFacetSection',
parentId: 'Nested'
},
// Search Term #MicroChartDataSection (Sub tab, take note of parentID)
{
purpose: #STANDARD,
type: #COLLECTION,
label: 'Micro Chart Data(#MicroChartDataSection)',
id: 'chartDataCollection',
parentId: 'Nested'
}
]
Search term: #DisplayTextAndID
Instead of showing unreadable long IDs, there is the option to replace the ID with another text property from the entity, for example a name property. The @ObjectModel.text.element
annotation specifies which value should be displayed instead of the original value.
Note
Source: CDS View /DMO/FSA_I_Criticality
@ObjectModel.text.element: ['Name']
key code as Code,
name as Name,
The @UI.textArrangement
annotation defines how the new text is displayed. The options are #TextOnly
, #TextFirst
, #TextLast
, #TextSeparate
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #DisplayTextAndID
@UI.textArrangement: #TEXT_FIRST,
CriticalityCode;
More Information: ABAP RESTful Application Programming Model: Providing Text by Text Elements in the Same Entity
Search term: #HidingContent
Any header facet, section or data field can be hidden with the annotation @UI.xx.hidden
. The annotation supports either fixed boolean values or values from a referenced property, as shown below.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #HidingContent
@UI.facet: [
{
purpose: #HEADER, // or #STANDARD
type: #FIELDGROUP_REFERENCE,
label: 'Section Visible when in Edit(#HidingContent)',
targetQualifier: 'ShowWhenInEdit',
hidden: #( IsActiveEntity )
}
]
@UI.fieldGroup: [ { qualifier: 'ShowWhenInEdit' }] // Search Term #HidingContent
StringProperty;
More Information: ABAP RESTful Application Programming Model: Hiding Fields Dynamically on the Object Page
Search term: #Preview
A reference facet in a collection facet is not shown after loading the app, when the reference facet has the @UI.facet.isPartOfPreview
annotation and it is set to false. The sub section is then hidden beneath a "Show more" button on the UI.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #Preview
@UI.facet: [
{
purpose: #STANDARD
type: #COLLECTION,
label: 'Micro Chart Data(#MicroChartDataSection)',
id: 'chartDataCollection'
},
{
parentId : 'chartDataCollection',
label : 'Chart Data Preview (#Preview)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'chartDataPreview',
isPartOfPreview: false
}
]
@UI.fieldGroup: [ { qualifier: 'chartDataPreview' }] // Search Term #Preview
IntegerValue;
Search term: #MultiInputField
It is possible to have a multi input field which displays values from an association. When the values are from a child entity with delete capability, you are able to delete the entity in edit mode, directly from the multi input field.
It is not necessary to use the @UI.fieldGroup
annotation to display the field, it is just annotated as such in the app to group and display it. It is however necessary, to use the datafield attribute value
to set the source of the input, in this case the field StringProperty
via the association _Child
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
{
// Search Term #OPForm
purpose: #HEADER, // or #STANDARD
label : 'FieldGroup (#OPForm)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'OPForm',
id: 'SubSectionID'
}
]
// Search Term #MultiInputField
@UI.fieldGroup: [
{
label: 'Multi Input Field (#MultiInputField)',
qualifier: 'OPForm',
value: '_Child.StringProperty',
position: 40
}
]
Child;
Search term: #PresentationVariant-Child
A presentation variant defines how the result of a queried collection of entities is shaped and how this result is displayed, for example as a list report or a chart (@UI.presentationVariant.visualizations
), the sorting order (@UI.presentationVariant.sortOrder
), or the number of items (@UI.presentationVariant.maxItems
) to display per segment.
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #PresentationVariant-Child
@UI.presentationVariant: [
{
qualifier: 'pVariant',
maxItems: 5,
sortOrder: [
{
by: 'StringProperty',
direction: #DESC
}
],
visualizations: [{type: #AS_LINEITEM}]
}
]
To use presentation variant for a child entity in the object page, it is necessary to annotate @UI.facet
with the correct type in the root entity: #PRESENTATIONVARIANT_REFERENCE
instead of #LINEITEM_REFERENCE
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #OPTable, #PresentationVariant-Child
@UI.facet: [
{
purpose: #STANDARD,
type: #PRESENTATIONVARIANT_REFERENCE,
targetElement: '_Child',
targetQualifier: 'pVariant',
label: 'Child Entity (1..n)(#OPTable)',
id: 'childEntitiesSection'
}
]
Search term: #SelectionVariant-Child
With a selection variant, you can define how the fields of an entity set should be filtered. The attribute text
is the title of the view and filter
contains all filter parameters.
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #SelectionVariant
@UI.selectionVariant: [
{
qualifier: 'sVariant',
text: 'SelectionVariant (Positive criticality)',
filter: 'CriticalityCode EQ 3'
}
]
Search term: #SelectionPresentationVariant-Child
A SelectionPresentationVariant bundles a Selection Variant and a Presentation Variant.
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #SelectionPresentationVariant-Child
@UI.selectionPresentationVariant: [
{
qualifier: 'ChildSP',
presentationVariantQualifier: 'pVariant',
selectionVariantQualifier: 'sVariant'
}
]
Search term: #ConnectedFields
When two properties are semantically connected, they can be displayed next to each other under one label, to show their data relation. The connected field is defined with the annotation @UI.connectedFields
. The attribute template
is a string which defines in which order the properties are displayed and what is displayed between both properties, for example a slash.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #ConnectedFields
@UI.connectedFields: [
{
qualifier: 'ConnectedFields',
groupLabel: 'Connected Fields (#ConnectedFields)',
name: 'integer',
template: '{integer} / {target}'
}
]
IntegerValue;
// Search Term #ConnectedFields
@UI.connectedFields: [
{
qualifier: 'ConnectedFields',
name: 'target'
}
]
TargetValue;
The connected field can only be displayed in a form using @UI.fieldGroup
or in a #STANDARD
facet. They cannot be rendered in a table with @UI.lineItem
, with @UI.identification
or in header facets.
@UI.facet: [
{
// Search Term #OPForm
purpose : #STANDARD,
label : 'FieldGroup (#OPForm)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'OPForm',
id: 'SubSectionID'
}
]
// Search Term #ConnectedFields
@UI.fieldGroup: [
{
qualifier: 'OPForm',
type: #AS_CONNECTED_FIELDS,
valueQualifier: 'ConnectedFields',
position: 10
}
]
IntegerValue;
Search term: #Stream
You can enable your RAP application for maintaining large objects (LOBs). By doing so, you provide end users the option to incorporate external binary files or text files when editing entity instances. First the appropriate fields should be added into the database table and the CDS view, and also the annotations @Semantics.largeObject
and @Semantics.mimeType
. To show it in a standard or header facet, you will need annotation @UI.facet
. Lastly, you should also update the mapping and the draft table in your behaviour definition.
Note
Source: Database Table /DMO/FSA_ChildA
stream_filename : abap.char(128);
stream_mimetype : abap.char(128);
stream_file : abap.rawstring(0);
Note
Source: CDS View /DMO/FSA_C_ChildTP
StreamFilename, // Search Term #Stream
// Search Term #Stream
@Semantics.largeObject: {
acceptableMimeTypes: [ 'image/*', 'application/*' ],
cacheControl.maxAge: #MEDIUM,
contentDispositionPreference: #INLINE, // #ATTACHMENT - download as file
// #INLINE - open in new window
fileName: 'StreamFilename',
mimeType: 'StreamMimeType'
}
StreamFile,
// Search Term #Stream
@Semantics.mimeType: true
StreamMimeType,
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #Stream
@UI.facet: [
{
purpose: #STANDARD,
type: #COLLECTION,
id: 'Collection',
label: 'Data'
},
{
purpose: #STANDARD
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Stream',
label: 'Large Object (#Stream)',
parentId: 'Collection'
}
]
// Search Term #Stream
@UI.hidden: true
StreamMimeType;
@UI.fieldGroup: [{ position: 10, qualifier: 'Stream', label: 'Attachment (#Stream)' }] // Search Term #Stream
StreamFile;
// Search Term #Stream
@UI.hidden: true
StreamFilename;
Note
Source: BDEF /DMO/FSA_R_ROOTTP
define behavior for /DMO/FSA_R_ChildTP alias Child {
...
mapping for /dmo/fsa_child_a {
..
StreamFile = stream_file;
StreamFilename = stream_filename;
StreamMimeType = stream_mimetype;
}
More Information on data modelling for Large Object: ABAP RESTful Application Programming Model - Working with Large Objects
Search term: #StreamStaticFeatureCtrl
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
It is possible to enable static field control for your large object property/attachment. This is done by adding the control in the behaviour definition.
In our example, we have set the stream property to readonly.
Note
Source: CDS View /DMO/FSA_C_ChildTP
// Search Term #StreamStaticFeatureCtrl
@Semantics.largeObject: {
acceptableMimeTypes: [ 'image/*', 'application/*' ],
cacheControl.maxAge: #MEDIUM,
contentDispositionPreference: #ATTACHMENT , // #ATTACHMENT - download as file
// #INLINE - open in new window
fileName: 'StreamFilename',
mimeType: 'StreamMimeType'
}
StreamFileReadonly,
StreamFilename,
@Semantics.mimeType: true
StreamMimeType,
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #StreamStaticFeatureCtrl
@UI: {
fieldGroup: [
{
position: 30,
qualifier: 'Stream',
label: 'Attachment (#StreamStaticFeatureCtrl)'
}
]
}
StreamFileReadonly;
// Search Term #Stream
@UI.hidden: true
StreamMimeType;
// Search Term #Stream
@UI.hidden: true
StreamFilename;
Note
Source: BDEF /DMO/FSA_R_ROOTTP
define behavior for /DMO/FSA_R_ChildTP alias Child .. {
field ( readonly ) StreamFileReadonly; // Search Term #StreamStaticFeatureCtrl
}
More Information: ABAP RESTful Application Programming Model - Static Feature Control
Search term: #StreamDynamicFeatureCtrl
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
It is possible to enable dynamic field control for your large object property/attachment. This is done by adding the control in the behaviour definition.
In our example, we set the stream property to readonly, when the boolean property StreamIsReadOnly
is set to true
. This can only be done when creating a new child instance, as the property StreamIsReadOnly
itself has field control readonly : update, mandatory : create
.
Note
Source: Database Table /DMO/FSA_ChildA
stream_filename : abap.char(128);
stream_mimetype : abap.char(128);
stream_file : abap.rawstring(0);
stream_is_readonly : abap_boolean;
Note
Source: CDS View /DMO/FSA_C_ChildTP
StreamIsReadOnly, // Search Term #StreamDynamicFeatureCtrl
StreamFilename, // Search Term #Stream
// Search Term #Stream
@Semantics.largeObject: {
acceptableMimeTypes: [ 'image/*', 'application/*' ],
cacheControl.maxAge: #MEDIUM,
contentDispositionPreference: #INLINE, // #ATTACHMENT - download as file
// #INLINE - open in new window
fileName: 'StreamFilename',
mimeType: 'StreamMimeType'
}
StreamFile,
// Search Term #Stream
@Semantics.mimeType: true
StreamMimeType,
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #StreamDynamicFeatureCtrl
@UI: {
fieldGroup: [
{
position: 10,
qualifier: 'Stream',
label: 'Stream readonly? (#StreamDynFeatureCtrl)'
}
]
}
@EndUserText: {
label: 'Stream readonly? Caution - cannot be changed after create',
quickInfo: 'Stream readonly?'
}
StreamIsReadOnly;
// Search Term #Stream
@UI.hidden: true
StreamMimeType;
@UI: {
// Search Term #Stream
fieldGroup: [
{
position: 10,
qualifier: 'Stream',
label: 'Attachment (#Stream)'
}
]
}
StreamFile;
// Search Term #Stream
@UI.hidden: true
StreamFilename;
Note
Source: BDEF /DMO/FSA_R_ROOTTP
define behavior for /DMO/FSA_R_ChildTP alias Child ... {
field ( readonly : update, mandatory : create ) StreamIsReadOnly;
...
mapping for /dmo/fsa_child_a {
StreamFile = stream_file;
StreamFilename = stream_filename;
StreamMimeType = stream_mimetype;
}
}
Note
Source: Behaviour Implementation /DMO/FSA_BP_R_ROOTTP
CLASS lhc_child IMPLEMENTATION.
METHOD get_instance_features.
READ ENTITIES OF /DMO/FSA_R_RootTP IN LOCAL MODE
ENTITY Child
FIELDS ( StreamIsReadOnly )
WITH CORRESPONDING #( keys )
RESULT DATA(children).
result = VALUE #( FOR child IN children
( %tky = child-%tky
%field-StreamFile = COND #( WHEN child-StreamIsReadOnly = abap_true
THEN if_abap_behv=>fc-f-read_only
ELSE if_abap_behv=>fc-f-unrestricted )
) ).
ENDMETHOD.
ENDCLASS.
More Information: ABAP RESTful Application Programming Model - Dynamic Feature Control
Search term: #OPDetermineAction
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
Determining actions are used to trigger actions directly using the context of the page in the object page, like an action that completes a process step (e.g. approve, reject). The action button will appear at the footer of the object page. This only works with @UI.identification
and keyword determining: true
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.identification: [
// Search Term #OPDetermineAction
{
type: #FOR_ACTION,
label: 'Change Criticality (#OPDetermineAction)',
criticality: 'CriticalityCode',
dataAction: 'changeCriticality',
determining: true
}
]
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
action changeCriticality parameter /DMO/FSA_D_ChangeCriticalityP result [1] $self;
Search term: #RAPTreeview, #RAPTreeviewSection
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release.
ABAP CDS allows for the structuring of data in hierarchies. For RAP, it is possible to display this CDS Hierarchy as a readonly treeview in the SAP Fiori UI, either as a list report which has a different implementation (an example can be found in ABAP RESTful Application Programming Model: Implementing Treeviews) or in the object page, which will be described hereafter.
The example implemented here represents a file folder system. Each folder has a parent folder, which is itself a 'normal' folder, and the topmost/root folder does not have a parent. Each folder is named with a combination of colour and number, and the name is used to sort the hiearchy. The root entity will serve as a 'directory' so that each instance has its own hierarchy which can be displayed in the object page.
To implement this you would need the following artifacts:
The root_id
contains the id of the directory, in this case the root instance. parent_folder
contains the folder_id
of the parent.
Note
Source: Database table /DMO/FSA_FLDR_A
define table /dmo/fsa_fldr_a {
key client : abap.clnt not null;
key root_id : sysuuid_x16 not null;
key folder_id : sysuuid_c22 not null;
parent_folder : sysuuid_c22;
folder_name : abap.char(1024);
folder_size : abap.dec(10,2);
}
It serves as the source for the hierarchy, has a self-association and an association to the root entity, the directory. Annotations depicting how the treeview is shown in UI is also declared here. The most important annotation, @OData.hierarchy.recursiveHierarchy
is required to specify the hierarchy.
Note
Source: CDS View /DMO/FSA_I_Folder
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: '(Hierarchy) Folder'
// Search Term #RAPTreeview
@OData.hierarchy.recursiveHierarchy: [{ entity.name: '/DMO/FSA_I_FolderHN' }]
@UI: {
headerInfo: {
typeName: 'Folder in Directory',
typeNamePlural: 'Folders in Directory',
title.value: 'FolderName'
},
presentationVariant: [
{
sortOrder: [{ by: 'FolderName', direction: #ASC }],
visualizations: [{type: #AS_LINEITEM}]
}
]
}
define view entity /DMO/FSA_I_Folder
as select from /dmo/fsa_fldr_a
association to one /DMO/FSA_I_Root as _Directory on $projection.RootId = _Directory.ID
association of many to one /DMO/FSA_I_Folder as _ParentFolder on $projection.RootId = _ParentFolder.RootId
and $projection.ParentFolder = _ParentFolder.FolderId
{
@UI.facet: [{
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Folder (#RAPTreeview)',
position: 10
}]
@UI.hidden: true
key root_id as RootId,
@UI.hidden: true
key folder_id as FolderId,
@UI: {
lineItem: [{
position: 30,
value: '_ParentFolder.FolderName',
label: 'Parent Folder'
}],
identification: [{
position: 30,
value: '_ParentFolder.FolderName',
label: 'Parent Folder'
}]
}
@EndUserText.label : 'Parent Folder'
parent_folder as ParentFolder,
@UI: {
lineItem: [{ position: 10 }],
identification: [{ position: 10 }]
}
@EndUserText.label : 'Name of Folder'
folder_name as FolderName,
@UI: {
lineItem: [{ position: 20 }],
identification: [{ position: 20 }]
}
@EndUserText.label : 'Size of Folder (in GB)'
folder_size as FolderSize,
_Directory,
_ParentFolder
}
The source of the hierarchy is /DMO/FSA_I_Folder
. The parent of a node is defined via association _ParentFolder
, which is a self-association. The hierarchy is filtered with parameter P_Directory
, which is the ID
of the root instance so that the correct hierarchy is shown in the object page of the instance. The topmost node is the one with an initial ParentFolder
and the hierarchy is sorted by FolderName
.
Note
Source: CDS View /DMO/FSA_I_FolderHN
define hierarchy /DMO/FSA_I_FolderHN
with parameters
P_Directory : sysuuid_x16
as parent child hierarchy (
source /DMO/FSA_I_Folder
child to parent association _ParentFolder
directory _Directory filter by
RootId = $parameters.P_Directory
start where ParentFolder is initial
siblings order by FolderName
)
{
key RootId,
key FolderId,
ParentFolder
}
The following artifacts must be modified:
An association to the hierarchy must be included in the root entity, since the root entity serves as a directory. The association _Folder
need to be exposed up until the consumption view /DMO/FSA_C_RootTP
.
Note
Source: CDS View /DMO/FSA_I_Root
define view entity /DMO/FSA_I_Root
...
association of exact one to many /DMO/FSA_I_Folder as _Folder // Search Term #RAPTreeview
on $projection.ID = _Folder.RootId
{
...
_Folder,
...
}
A facet is added to show the treeview as a list report within the object page.
Note
Source: Metadata Extension /DMO/FSA_C_FolderTP
annotate entity /DMO/FSA_C_RootTP with
{
@UI.facet: [
// Search Term #RAPTreeviewSection
{
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
label: 'File Folder System (#RAPTreeviewSection)',
targetElement: '_Folder'
}
]
}
The hierarchy CDS View should be exposed in the service.
Note
Source: Service Definition /DMO/UI_FeatureShowcaseApp
define service /DMO/UI_FeatureShowcaseApp {
...
expose /DMO/FSA_I_Folder as Folder;
}
More Information:
- ABAP Data Models: CDS Hierarchies
- ABAP RESTful Application Programming Model: Implementing Treeviews
Search term: #ActionInSection
Sections can have their own actions, which show up in the upper right corner of the section by default. This is done through annotation @UI.facet
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search Term #OPForm
{
purpose : #HEADER, // or #STANDARD,
label : 'FieldGroup (#OPForm)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'OPForm',
id: 'SubSectionID'
}
]
// Search Term #ActionInSection
@UI.fieldGroup: [
{
qualifier: 'OPForm',
dataAction: 'changeProgress',
type: #FOR_ACTION,
emphasized: true,
criticality: 'CriticalityCode',
label: 'Change Progress (#ActionInSection)'
}
]
LastChangedAt;
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
action changeProgress parameter /DMO/FSA_D_ChangeProgressP result [1] $self;
Search term: #InlineActionInForm
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
Forms can also have their own actions, which show up in the upper right corner of the form by default. This is done through annotation @UI.facet
and UI.fieldGroup.inline: true
.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search Term #OPForm
{
purpose : #HEADER, // or #STANDARD,
label : 'FieldGroup (#OPForm)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'OPForm',
id: 'SubSectionID'
}
]
// Search Term #InlineActionInForm
@UI.fieldGroup: [
{
qualifier: 'OPForm',
dataAction: 'changeCriticality',
type: #FOR_ACTION,
emphasized: true,
inline: true,
label: 'Change Criticality (#InlineActionInForm)'
}
]
LastChangedAt;
Note
Source: Behaviour Definition /DMO/FSA_R_RootTP
action changeProgress parameter /DMO/FSA_D_ChangeProgressP result [1] $self;
Search term: #SectionNavigation, #FormNavigation
External or intent based navigations are added in the App using @UI.fieldGroup
. Depending on the type used (#FOR_INTENT_BASED_NAVIGATION
or #WITH_INTENT_BASED_NAVIGATION
), the navigation will either be rendered as a button at the section toolbar or a link.
An intent is the combination of an action and semantic object. There are 2 ways to achieve this.
Associating the semantic object using @Consumption.semanticObject
and keyword semanticObjectAction
in the UI anotation.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search Term #OPForm
{
purpose : #HEADER, // or #STANDARD,
label : 'FieldGroup (#OPForm)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'OPForm',
id: 'SubSectionID'
}
]
@Consumption.semanticObject: 'FeatureShowcaseNavigation'
@UI: {
fieldGroup: [
// Search Term #SectionNavigation ( Button )
{
qualifier: 'OPForm',
label: 'IntentBased Navi (#SectionNavigation)',
type: #FOR_INTENT_BASED_NAVIGATION,
semanticObjectAction: 'manage'
},
// Search Term #FormNavigation ( Link )
{
qualifier: 'OPForm',
label: 'IntentBased Navi (#FormNavigation)',
type: #WITH_INTENT_BASED_NAVIGATION,
value: 'NavigationID',
semanticObjectAction: 'manage',
position: 50
}
]
}
NavigationID;
Search term: #UISemanticObject
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
Associating the semantic object using keywords semanticObject, semanticObjectAction
in the UI anotation.
Additionally you may set the binding if different values are to be used. You can use either localElement
for a property in the CDS view, or localParameter
for a CDS parameter.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
@UI.facet: [
// Search Term #HeaderCollectionFacet
{
purpose: #HEADER,
id: 'FacetCollection',
type: #COLLECTION
},
// Search Term #HeaderFieldGroup
{
parentId : 'FacetCollection',
label : 'General Data (#HeaderFieldGroup)',
type : #FIELDGROUP_REFERENCE,
targetQualifier: 'HeaderData'
}
]
@UI: {
fieldGroup: [
// Search Term #UISemanticObject
{
qualifier: 'HeaderData',
position: 40,
label: 'IntentBased Navi (#UISemanticObject)',
type: #WITH_INTENT_BASED_NAVIGATION,
semanticObject: 'FeatureShowcaseContact',
semanticObjectAction: 'manage',
semanticObjectBinding: [{ localElement: 'Country', element: 'Country' }]
}
]
}
ContactID;
More Information: ABAP RESTful Application Programming Model: Based on Intent
Search term: #OPTable
Table sections are most commonly for child entities or other associated entities. The implementation consists of two parts. First the associated or child entity needs the @UI.lineItem
annotation. This defines which fields are displayed.
Note
Source: Metadata Extension /DMO/FSA_C_GrandchildTP
@UI.lineItem: [{ position: 10 }] // Search Term #OPTable
StringProperty;
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
Secondly the @UI.facet
annotation needs to be added
// Search Term #OPTable
@UI.facet: [
{
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
targetElement: '_Grandchild',
label: 'Grandchild Entities (1..n)(#OPTable)'
}
]
Additionally it is also possible to show a table in a facet using the type #SELECTIONPRESENTATIONVARIANT_REFERENCE
.
First the associated or child entity needs @UI.presentationVariant
, @UI.selectionVariant
, @UI.selectionPresentationvariant
and @UI.lineItem
annotation. This defines which fields are displayed.
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #OPTable
@UI: {
// Search Term #PresentationVariant-Child
presentationVariant: [
{
qualifier: 'pVariant',
sortOrder: [
{
by: 'StringProperty',
direction: #DESC
}
],
visualizations: [{type: #AS_LINEITEM}]
}
],
// Search Term #SelectionVariant-Child
selectionVariant: [
{
qualifier: 'sVariant',
text: 'SelectionVariant (Positive criticality)',
filter: 'CriticalityCode EQ 3'
}
],
// Search Term #SelectionPresentationVariant-Child
selectionPresentationVariant: [
{
presentationVariantQualifier: 'pVariant',
selectionVariantQualifier: 'sVariant'
}
]
}
annotate entity /DMO/FSA_C_ChildTP
with
{
...
@UI.lineItem: [{ position: 10 }] // Search Term #OPTable
StringProperty;
@UI.lineItem: [{ position: 20 }] // Search Term #OPTable
FieldWithPercent;
@UI.lineItem: [{
position: 30,
criticality: 'CriticalityCode'
}]
BooleanProperty;
}
Secondly the @UI.facet
annotation needs to be added.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #OPTable, #PresentationVariant-Child, #SelectionPresentationVariant-Child, #SelectionVariant-Child
@UI.facet: [
{
purpose: #STANDARD,
type: #SELECTIONPRESENTATIONVARIANT_REFERENCE,
targetElement: '_Child',
label: 'Child Entity (1..n)(#OPTable)',
id: 'childEntitiesSection'
}
]
More Information: ABAP RESTful Application Programming Model: Tables
Search term: #OPTableTitle
The title of an Object Page table is the attribute typeNamePlural
of the @UI.headerInfo
annotation.
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search Term #HeaderInfo
@UI.headerInfo: {
...
typeNamePlural: 'Root Entities (#OPTableTitle)', // Search Term #OPTableTitle
...
}
If the section title and the table title are identical or the @UI.headerInfo
annotation is not given, the table title will not be displayed. Also if the table is the only content in a subsection and has a title, the subsections title will not be displayed.
Search term: #ActionOverload
Warning
Only available with the latest SAP BTP or SAP S/4HANA Cloud, public edition release and for SAP S/4HANA, on-premise edition or SAP S/4HANA Cloud, private edition, from release 2023 onwards.
Action overload means to add an action bound to another entity, to the object page list table of a child entity. The action is defined in the behaviour definition, and the UI annotation to add the action is defined in the other entity's CDS view or metadata extension.
The example given here, is an action button displayed at the Child entity table in section Child Entity (1..n)(#OPTable), that calls a Root action to create a new Child instance.
Note
Source: Behaviour Definition /DMO/FSA_C_RootTP
define behavior for /DMO/FSA_C_RootTP alias Root
{
action ( features : instance ) createChildFromRoot result [0..1] entity /DMO/FSA_C_ChildTP;
}
Note
Source: Metadata Extension /DMO/FSA_C_ChildTP
// Search Term #ActionOverload
@UI.lineItem: [
{
type: #FOR_ACTION,
dataAction: '/DMO/FSA_C_RootTP.createChildFromRoot',
label: 'Create Child from Root (#ActionOverload)'
}
]
StringProperty;
Search term: #ChartSection
As an alternative to micro charts in the header, charts are also possible as sections. However the implementation is more complex. As aggregation is not yet available for V4 services, which this app is based on, the following shows only an example of how a chart should be annotated.
First the entity needs @Aggregation.default
annotations, which defines which aggregation methods are supported. This can only be done on views that are not transactional.
Note
Source: CDS View /DMO/FSA_I_Chart
define view entity /DMO/FSA_I_Chart
as select from zfsa_chart_a
...
{
key id as ID,
...
@EndUserText.label : 'Minimal Net Amount'
@Aggregation.default: #MIN
integer_value as MinAmount,
@EndUserText.label : 'Maximal Net Amount'
@Aggregation.default: #MAX
integer_value as MaxAmount,
@EndUserText.label : 'Average Net Amount'
@Aggregation.default: #AVG
integer_value as AvgAmount,
...
}
After that the @UI.chart
can be defined. Please note, that the attribute measures
contains the properties of the aggregation methods. If it is just a property of the entity, like "integerValue", the chart won't be displayed. The first property in the attribute dimensions
has the default dimension. The second property is the category into which a drill down is possible.
The added actions to the attribute actions
are shown in the chart toolbar.
Note
Source: CDS View /DMO/FSA_C_ChartTP
// Search Term #ChartSection
@UI.chart: [
{
qualifier: 'Test',
title: 'Chart (#ChartSection)',
chartType: #COLUMN,
dimensions: ['Dimensions', 'CriticalityCode'],
measures: ['MaxAmount'],
dimensionAttributes: [
{
dimension: 'Dimensions',
role: #CATEGORY
},
{
dimension: 'CriticalityCode',
role: #CATEGORY
}
],
measureAttributes: [
{
measure: 'MaxAmount',
role: #AXIS_1
}
],
actions: [{ type: #FOR_ACTION, dataAction: 'updateChart', label: 'Action at Chart' }]
}
]
Lastly the chart needs to be added to the @UI.facet
annotation.
:warning: This section is commented out in the Feature Showcase App as Aggregation annotations are still not yet available in V4 services
Note
Source: Metadata Extension /DMO/FSA_C_RootTP
// Search term #ChartSection
@UI.facet: [
{
id: 'chart',
purpose: #STANDARD,
type: #CHART_REFERENCE,
targetElement: '_Chart',
label: 'Chart (#ChartSection)'
}
]
For semantic coloring of a dimension, the dimension property "CriticalityCode" is annotated with @UI.valueCriticality
, where possible values of the property are matched against a criticality.
Note
Source: Metadata Extension /DMO/FSA_C_ChartTP
// Search Term #ChartSection
@UI.valueCriticality: [
{
value: '1',
criticality: #NEGATIVE
},
{
value: '2',
criticality: #CRITICAL
},
{
value: '3',
criticality: #POSITIVE
}
]
CriticalityCode;
More Information: ABAP RESTful Application Programming Model: Visualizing Data with Charts